[CodeChef-QTREE]Queries on tree again!
Posted skylee的OI博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CodeChef-QTREE]Queries on tree again!相关的知识,希望对你有一定的参考价值。
题目大意:
给定一个环长为奇数的带权基环树,支持以下两种操作:
1.两点间最短路取反;
2.两点间最短路求最大子段和。
思路:
首先找出环,然后对每一个外向树轻重链剖分,
用线段树维护每一个区间的和、前缀和最值、后缀和最值及子段最值。
每次修改时,分下列两种情况讨论:
1.两个点在同一棵外向树上,按照普通的树链剖分修改,线段树上打取反的标记。
2.两个点再不同外向树上,先各自沿着链往上跳,然后都跳到环上的时候,可以将两个点在环中的序号减一减,对环长取模,看看哪个小。
查询时大致和修改一样,但是合并两个区间的时候很麻烦,要注意考虑完全。
细节:
1.找环可以在DFS的时候和树剖一起完成,也可以用并查集写,两个效率差不多。
2.标记可以打好几次,所以不能简单地把标记赋值为true,而是每次取反。
这题代码量比较大,vjudge上除了周骏东都是10K左右。网上的题解也很少,中英文都没有找到。
一开始写挂的地方特别多,对拍对了好多次才排出所有的错。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 inline int getint() { 5 char ch; 6 bool neg=false; 7 while(!isdigit(ch=getchar())) if(ch==‘-‘) neg=true; 8 int x=ch^‘0‘; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^‘0‘); 10 return neg?-x:x; 11 } 12 const int V=100001; 13 struct Edge { 14 int to,w; 15 }; 16 std::vector<Edge> e[V]; 17 inline void add_edge(const int u,const int v,const int w) { 18 e[u].push_back((Edge){v,w}); 19 } 20 int par[V],size[V],son[V],cyc[V],id[V],w[V],root[V],dep[V],top[V]; 21 int cnt_cyc,cnt; 22 bool on_cycle[V]; 23 bool dfs1(const int x,const int p) { 24 if(par[x]||(x==1&&p!=0)) { 25 on_cycle[x]=true; 26 return true; 27 } 28 size[x]=1; 29 par[x]=p; 30 bool flag=false; 31 for(unsigned i=0;i<e[x].size();i++) { 32 int &y=e[x][i].to; 33 if(y==p||on_cycle[y]) continue; 34 if(dfs1(y,x)) { 35 par[x]=0; 36 id[y]=++cnt; 37 w[cnt]=e[x][i].w; 38 if(on_cycle[x]) { 39 flag=true; 40 } else { 41 on_cycle[x]=true; 42 } 43 } else { 44 size[x]+=size[y]; 45 if(size[y]>size[son[x]]) son[x]=y; 46 } 47 } 48 if(on_cycle[x]) cyc[++cnt_cyc]=x; 49 return on_cycle[x]^flag; 50 } 51 int rt; 52 void dfs2(const int x) { 53 dep[x]=dep[par[x]]+1; 54 top[x]=x==son[par[x]]?top[par[x]]:x; 55 root[x]=cyc[rt]; 56 if(son[x]) { 57 id[son[x]]=++cnt; 58 dfs2(son[x]); 59 } 60 for(unsigned i=0;i<e[x].size();i++) { 61 int &y=e[x][i].to; 62 if(y==par[x]||on_cycle[y]) continue; 63 if(y==son[x]) { 64 w[id[y]]=e[x][i].w; 65 continue; 66 } 67 id[y]=++cnt; 68 w[cnt]=e[x][i].w; 69 dfs2(y); 70 } 71 } 72 void dfs3(const int x,const int p) { 73 par[x]=p; 74 son[x]=0; 75 size[x]=1; 76 for(unsigned i=0;i<e[x].size();i++) { 77 int &y=e[x][i].to; 78 if(y==p||on_cycle[y]) continue; 79 dfs3(y,x); 80 size[x]+=size[y]; 81 if(size[y]>size[son[x]]) son[x]=y; 82 } 83 } 84 class SegmentTree { 85 private: 86 int left[V<<1],right[V<<1]; 87 long long sum[V<<1],submax[V<<1],submin[V<<1],premax[V<<1],premin[V<<1],sufmax[V<<1],sufmin[V<<1]; 88 bool neg[V<<1]; 89 int sz,newnode() { 90 return ++sz; 91 } 92 void negate(long long &x) { 93 x=-x; 94 } 95 void reverse(const int p) { 96 negate(sum[p]); 97 negate(submax[p]); 98 negate(submin[p]); 99 std::swap(submax[p],submin[p]); 100 negate(premax[p]); 101 negate(premin[p]); 102 std::swap(premax[p],premin[p]); 103 negate(sufmax[p]); 104 negate(sufmin[p]); 105 std::swap(sufmax[p],sufmin[p]); 106 } 107 void push_up(const int p) { 108 sum[p]=sum[left[p]]+sum[right[p]]; 109 submax[p]=std::max(std::max(submax[left[p]],submax[right[p]]),sufmax[left[p]]+premax[right[p]]); 110 submin[p]=std::min(std::min(submin[left[p]],submin[right[p]]),sufmin[left[p]]+premin[right[p]]); 111 premax[p]=std::max(premax[left[p]],sum[left[p]]+premax[right[p]]); 112 premin[p]=std::min(premin[left[p]],sum[left[p]]+premin[right[p]]); 113 sufmax[p]=std::max(sufmax[right[p]],sum[right[p]]+sufmax[left[p]]); 114 sufmin[p]=std::min(sufmin[right[p]],sum[right[p]]+sufmin[left[p]]); 115 } 116 void push_down(const int p) { 117 if(!neg[p]) return; 118 reverse(left[p]); 119 reverse(right[p]); 120 neg[p]=false; 121 neg[left[p]]=!neg[left[p]]; 122 neg[right[p]]=!neg[right[p]]; 123 } 124 public: 125 struct Ans { 126 long long sum,pre,sub,suf; 127 }; 128 int root; 129 void build(int &p,const int b,const int e) { 130 p=newnode(); 131 if(b==e) { 132 sum[p]=w[b]; 133 submax[p]=premax[p]=sufmax[p]=std::max(w[b],0); 134 submin[p]=premin[p]=sufmin[p]=std::min(w[b],0); 135 return; 136 } 137 int mid=(b+e)>>1; 138 build(left[p],b,mid); 139 build(right[p],mid+1,e); 140 push_up(p); 141 } 142 void modify(const int p,const int b,const int e,const int l,const int r) { 143 if((b==l)&&(e==r)) { 144 reverse(p); 145 neg[p]=!neg[p]; 146 return; 147 } 148 push_down(p); 149 int mid=(b+e)>>1; 150 if(l<=mid) modify(left[p],b,mid,l,std::min(mid,r)); 151 if(r>mid) modify(right[p],mid+1,e,std::max(mid+1,l),r); 152 push_up(p); 153 } 154 Ans query(const int p,const int b,const int e,const int l,const int r) { 155 if((b==l)&&(e==r)) { 156 return (Ans){sum[p],premax[p],submax[p],sufmax[p]}; 157 } 158 push_down(p); 159 int mid=(b+e)>>1; 160 long long leftsum=0,leftpre=0,leftsub=0,leftsuf=0,rightsum=0,rightpre=0,rightsub=0,rightsuf=0; 161 if(l<=mid) { 162 Ans tmp=query(left[p],b,mid,l,std::min(mid,r)); 163 leftsum=tmp.sum; 164 leftpre=tmp.pre; 165 leftsub=tmp.sub; 166 leftsuf=tmp.suf; 167 } 168 if(r>mid) { 169 Ans tmp=query(right[p],mid+1,e,std::max(mid+1,l),r); 170 rightsum=tmp.sum; 171 rightpre=tmp.pre; 172 rightsub=tmp.sub; 173 rightsuf=tmp.suf; 174 } 175 long long sum,pre,sub,suf; 176 sum=leftsum+rightsum; 177 pre=std::max(leftpre,leftsum+rightpre); 178 sub=std::max(std::max(leftsub,rightsub),leftsuf+rightpre); 179 suf=std::max(rightsuf,rightsum+leftsuf); 180 return (Ans){sum,pre,sub,suf}; 181 } 182 }; 183 SegmentTree t; 184 int n; 185 inline void modify(int x,int y) { 186 if(root[x]!=root[y]) { 187 while(top[x]!=root[x]) { 188 t.modify(t.root,1,n,id[top[x]],id[x]); 189 x=par[top[x]]; 190 } 191 if(x!=top[x]) { 192 t.modify(t.root,1,n,id[son[top[x]]],id[x]); 193 x=top[x]; 194 } 195 while(top[y]!=root[y]) { 196 t.modify(t.root,1,n,id[top[y]],id[y]); 197 y=par[top[y]]; 198 } 199 if(y!=top[y]) { 200 t.modify(t.root,1,n,id[son[top[y]]],id[y]); 201 y=top[y]; 202 } 203 } else { 204 while(top[x]!=top[y]) { 205 if(dep[top[x]]<dep[top[y]]) std::swap(x,y); 206 t.modify(t.root,1,n,id[top[x]],id[x]); 207 x=par[top[x]]; 208 } 209 if(x!=y) { 210 if(dep[x]<dep[y]) std::swap(x,y); 211 t.modify(t.root,1,n,id[son[y]],id[x]); 212 } 213 return; 214 } 215 if((id[y]-id[x]+cnt_cyc)%cnt_cyc>(id[x]-id[y]+cnt_cyc)%cnt_cyc) std::swap(x,y); 216 if(id[x]<id[y]) { 217 t.modify(t.root,1,n,id[x],id[y]-1); 218 } else { 219 t.modify(t.root,1,n,id[x],cnt_cyc); 220 if(id[y]!=1) t.modify(t.root,1,n,1,id[y]-1); 221 } 222 } 223 inline long long query(int x,int y) { 224 long long lastsum=0,lastpre=0,lastsub=0,lastsuf=0,nextsum=0,nextpre=0,nextsub=0,nextsuf=0; 225 long long ans=0; 226 if(root[x]!=root[y]) { 227 while(top[x]!=root[x]) { 228 SegmentTree::Ans tmp=t.query(t.root,1,n,id[top[x]],id[x]); 229 lastsub=std::max(std::max(lastsub,tmp.sub),lastpre+tmp.suf); 230 lastpre=std::max(tmp.pre,lastpre+tmp.sum); 231 lastsuf=std::max(lastsuf,lastsum+tmp.suf); 232 lastsum+=tmp.sum; 233 ans=std::max(ans,lastsub); 234 x=par[top[x]]; 235 } 236 if(x!=top[x]) { 237 SegmentTree::Ans tmp=t.query(t.root,1,n,id[son[top[x]]],id[x]); 238 lastsub=std::max(std::max(lastsub,tmp.sub),lastpre+tmp.suf); 239 lastpre=std::max(tmp.pre,lastpre+tmp.sum); 240 lastsuf=std::max(lastsuf,lastsum+tmp.suf); 241 lastsum+=tmp.sum; 242 ans=std::max(ans,lastsub); 243 x=top[x]; 244 } 245 while(top[y]!=root[y]) { 246 SegmentTree::Ans tmp=t.query(t.root,1,n,id[top[y]],id[y]); 247 nextsub=std::max(std::max(nextsub,tmp.sub),nextpre+tmp.suf); 248 nextpre=std::max(tmp.pre,nextpre+tmp.sum); 249 nextsuf=std::max(nextsuf,nextsum+tmp.suf); 250 nextsum+=tmp.sum; 251 ans=std::max(ans,nextsub); 252 y=par[top[y]]; 253 } 254 if(y!=top[y]) { 255 SegmentTree::Ans tmp=t.query(t.root,1,n,id[son[top[y]]],id[y]); 256 nextsub=std::max(std::max(nextsub,tmp.sub),nextpre+tmp.suf); 257 nextpre=std::max(tmp.pre,nextpre+tmp.sum); 258 nextsuf=std::max(nextsuf,nextsum+tmp.suf); 259 nextsum+=tmp.sum; 260 ans=std::max(ans,nextsub); 261 y=top[y]; 262 } 263 } else { 264 while(top[x]!=top[y]) { 265 if(dep[top[x]]<dep[top[y]]) { 266 std::swap(x,y); 267 std::swap(lastsum,nextsum); 268 std::swap(lastsub,nextsub); 269 std::swap(lastpre,nextpre); 270 std::swap(lastsuf,nextsuf); 271 } 272 SegmentTree::Ans tmp=t.query(t.root,1,n,id[top[x]],id[x]); 273 lastsub=std::max(std::max(lastsub,tmp.sub),lastpre+tmp.suf); 274 lastpre=std::max(tmp.pre,lastpre+tmp.sum); 275 lastsuf=std::max(lastsuf,lastsum+tmp.suf); 276 lastsum+=tmp.sum; 277 ans=std::max(ans,lastsub); 278 x=par[top[x]]; 279 } 280 if(x!=y) { 281 if(dep[x]<dep[y]) { 282 std::swap(x,y); 283 std::swap(lastsum,nextsum); 284 std::swap(lastsub,nextsub); 285 std::swap(lastpre,nextpre); 286 std::swap(lastsuf,nextsuf); 287 } 288 SegmentTree::Ans tmp=t.query(t.root,1,n,id[son[y]],id[x]); 289 lastsub=std::max(std::max(lastsub,tmp.sub),lastpre+tmp.suf); 290 lastpre=std::max(tmp.pre,lastpre+tmp.sum); 291 lastsuf=std::max(lastsuf,lastsum+tmp.suf); 292 lastsum+=tmp.sum; 293 } 294 ans=std::max(ans,std::max(lastsub,lastpre+nextpre)); 295 return ans; 296 } 297 if((id[y]-id[x]+cnt_cyc)%cnt_cyc>(id[x]-id[y]+cnt_cyc)%cnt_cyc) { 298 std::swap(x,y); 299 std::swap(lastsum,nextsum); 300 std::swap(lastsub,nextsub); 301 std::swap(lastpre,nextpre); 302 std::swap(lastsuf,nextsuf); 303 } 304 SegmentTree::Ans tmp; 305 if(id[x]<id[y]) { 306 tmp=t.query(t.root,1,n,id[x],id[y]-1); 307 } else { 308 SegmentTree::Ans tmp1,tmp2; 309 tmp1=t.query(t.root,1,n,id[x],cnt_cyc); 310 if(id[y]!=1) tmp2=t.query(t.root,1,n,1,id[y]-1); 311 if(id[y]!=1) { 312 tmp.sum=tmp1.sum+tmp2.sum; 313 tmp.sub=std::max(std::max(tmp1.sub,tmp2.sub),tmp1.suf+tmp2.pre); 314 tmp.pre=std::max(tmp1.pre,tmp1.sum+tmp2.pre); 315 tmp.suf=std::max(tmp2.suf,tmp2.sum+tmp1.suf); 316 } else { 317 tmp=tmp1; 318 } 319 } 320 ans=std::max(ans,tmp.sub); 321 ans=std::max(ans,lastpre+tmp.pre); 322 ans=std::max(ans,nextpre+tmp.suf); 323 ans=std::max(ans,lastpre+nextpre+tmp.sum); 324 return ans; 325 } 326 int main() { 327 n=getint(); 328 for(int i=1;i<=n;i++) { 329 int u=getint(),v=getint(),w=getint(); 330 add_edge(u,v,w); 331 add_edge(v,u,w); 332 } 333 dfs1(1,0); 334 for(rt=1;rt<=cnt_cyc;rt++) { 335 if(rt==cnt_cyc) dfs3(cyc[rt],0); 336 dfs2(cyc[rt]); 337 } 338 t.build(t.root,1,n); 339 for(int m=getint();m;m--) { 340 char op[2]; 341 scanf("%1s",op); 342 switch(op[0]) { 343 case ‘f‘: { 344 int x=getint(),y=getint(); 345 modify(x,y); 346 break; 347 } 348 case ‘?‘: { 349 int x=getint(),y=getint(); 350 printf("%lld\n",query(x,y)); 351 break; 352 } 353 } 354 } 355 return 0; 356 }
附数据生成器:
1 #include<ctime> 2 #include<vector> 3 #include<cstdio> 4 #include<cstdlib> 5 const int V=100001; 6 std::vector<int> e[V]; 7 inline void add_edge(const int u,const int v) { 8 e[u].push_back(v); 9 } 10 int par[V],dep[V],top[V],son[V],size[V]; 11 void dfs1(const int x) { 12 size[x]=1; 13 dep[x]=dep[par[x]]+1; 14 for(unsigned i=0;i<e[x].size();i++) { 15 int &y=e[x][i]; 16 dfs1(y); 17 size[x]+=size[y]; 18 if(size[y]>size[son[x]]) son[x]=y; 19 } 20 } 21 void dfs2(const int x) { 22 top[x]=x==son[par[x]]?top[par[x]]:x; 23 for(unsigned i=0;i<e[x].size();i++) { 24 int &y=e[x][i]; 25 dfs2(y); 26 } 27 } 28 inline int get_lca(int x,int y) { 29 while(top[x]!=top[y]) { 30 if(dep[top[x]]<dep[top[y]]) std::swap(x,y); 31 x=par[top[x]]; 32 } 33 if(dep[x]<dep[y]) std::swap(x,y); 34 return y; 35 } 36 int main() { 37 srand(time(NULL)); 38 int n=100000,m=100000,w=20001; 39 printf("%d\n",n); 40 for(int i=2;i<=n;i++) { 41 printf("%d %d %d\n",par[i]=rand()%(i-1)+1,i,rand()%w-w/2); 42 add_edge(par[i],i); 43 } 44 dfs1(1); 45 dfs2(1); 46 for(int i=1;i<n;i++) { 47 if(i!=par[n]) { 48 int lca=get_lca(i,n); 49 if((dep[i]+dep[n]-dep[lca]*2)&1) continue; 50 printf("%d %d %d\n",i,n,rand()%w-w/2); 51 break; 52 } 53 } 54 printf("%d\n",m); 55 for(int i=1;i<=m;i++) { 56 int op=rand()%2; 57 if(op) { 58 int y=rand()%(n-2)+2; 59 int x=rand()%(y-1)+1; 60 printf("? %d %d\n",x,y); 61 } else { 62 int y=rand()%(n-2)+2; 63 int x=rand()%(y-1)+1; 64 printf("f %d %d\n",x,y); 65 } 66 } 67 return 0; 68 }
以上是关于[CodeChef-QTREE]Queries on tree again!的主要内容,如果未能解决你的问题,请参考以下文章
Array Queries CodeForces - 797E
HDU - 5412 CRB and Queries (整体二分)