1. 程式人生 > >[CodeChef-QTREE]Queries on tree again!

[CodeChef-QTREE]Queries on tree again!

lca srand pla 兩種 == 大致 給定 比較 include

題目大意:
  給定一個環長為奇數的帶權基環樹,支持以下兩種操作:
    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 }
View Code

[CodeChef-QTREE]Queries on tree again!