A few days ago to fill in the pit of the reconstruction plan accidentally found their own tree division has been a place a bit bug, is the wrong qaq (but seems to have little impact
So the King de Yao World, hurriedly went to find a few tree division to practice
The bug is the W array that the sum directly uses when the tree is divided to find the center of gravity, but for each layer of the W array to recalculate (yet I'm not qaq
WC2010 Redevelopment Programme
This is a bug-heavy code, I used 19min finish, hand over 1A
But then I found out there were at least three errors in the code. Qaq the data is too weak.
Stick to a bug-heavy code, and by the way exercise to find bug ability?
The procedure is to-mid each edge after the two-point answer, judging whether there is a path of edge and >=0
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include < Cstdlib> #define EPS 1e-5using namespace std; const int Maxn=100010;const int Oo=0x7fffffff/3;int n,l,r,tmp;int u,v,b;int mn,mx;double ans,l,r;int h[maxn],cnt=0; struct edge{int to,next,w;} G[maxn<<1];int g,sum;int f[maxn],w[maxn];int son[maxn],tot=0;double fa[maxn];d ouble DEP[MAXN],MX_DEP[MAXN]; int Q[maxn];bool VIS[MAXN]; BOOL CMP (const int &A,CONST int &b) {return w[a]<w[b];} void Add (int x,int y,int z) {++cnt; G[cnt].to=y; G[CNT].NEXT=H[X]; g[cnt].w=z;h[x]=cnt;} void read (int &num) {Num=0;char Ch=getchar (); while (ch< '! ') Ch=getchar (); while (ch>= ' 0 ' &&ch<= ' 9 ') num=num*10+ch-' 0 ', Ch=getchar ();} void Cmax (int &a,int b) {if (b>a) a=b;} void get_g (int u,int fa) {f[u]=0;w[u]=1; for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (vis[v]| | V==FA) continue; Get_g (V,u); W[U]+=W[V]; Cmax (F[u],w[v]); }cMax (F[u],sum-w[u]); if (F[g]>f[u]) g=u;} void Get_dis (int u,int f,int d,double dis,double k) {if (d>tmp) Tmp=d; if (Dep[d]<dis) Dep[d]=dis; for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (vis[v]| | V==F) continue; Get_dis (V,U,D+1,DIS+G[I].W-K,K); }return;} BOOL Check (int u,double k) {int len=0;tmp=0; for (int i=1;i<=w[u];++i) Mx_dep[i]=-oo; for (int i=1;i<=tot;++i) {int v=son[i];tmp=0; for (int j=1;j<=w[v];++j) Dep[j]=-oo; Get_dis (V,-1,1,FA[V]-K,K); int now=0,h=0,t=-1; for (int j=tmp;j>=1;--j) {if (r-j<0) continue; while (Now<=r-j&&now<=len) {while (H<=t&&mx_dep[now]>mx_dep[q[t]]) t--; q[++t]=now;now++; } while (H<=t&&q[h]<l-j) h++; if (h<=t&&mx_dep[q[h]]+dep[j]>0) return true; } if (Tmp>len) len=tmp; for (int i=1;i<=len;++i) Mx_dep[i]=max (mx_dep[I],dep[i]); }return false;} void Get_ans (int u) {l=ans;r=mx; tot=0; for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (Vis[v]) continue; SON[++TOT]=V;FA[V]=G[I].W; } sort (son+1,son+tot+1,cmp); while (r-l>eps) {double mid= (l+r)/2.0; if (check (u,mid)) L=mid; else R=mid; }ans=l;} void Get_div (int u) {vis[u]=true; Get_ans (U); for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (Vis[v]) continue; sum=w[v];g=0; Get_g (v,-1); Get_div (g); }return;} int main () {scanf ("%d%d%d", &n,&l,&r); Mn=oo;mx=-oo; for (int i=1;i<n;++i) {read (u); Read (v); Read (b); Add (u,v,b); add (v,u,b); Mx=max (mx,b); Mn=min (mn,b); }ANS=MN; F[0]=oo;g=0;sum=n; Get_g (1,-1); Get_div (g); printf ("%.3lf\n", ans); return 0;}
The three bugs I found are:
1, W array is not recalculated (empty MX_DEP and DEP also use the W array, actually no WA)
2, I cycle there is another I cycle
3, before processing no sub-tree sorting, easy to be stuck into O (n^2)
SPOJ free Travel
Show technology forced to write O (NLOGN)
It's the same as rebuilding the plan, but it's a bug-free code.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include < cstdlib>using namespace Std;const int maxn=400010;const int oo=0x7fffffff/3;int n,k,m,tmp;int U,v,a;bool BLACK[MAXN] ; bool Vis[maxn];int h[maxn],cnt=0;int ans=0;struct edge{int to,next,w;} G[maxn<<1];int g,sum;int f[maxn],w[maxn],b[maxn];int son[maxn],tot=0;int fa[maxn],Q[maxn];int dep[maxn],mx_ Dep[maxn];bool CMP (const int &X,CONST int &y) {return b[x]<b[y];} void Add (int x,int y,int z) {++cnt; G[cnt].to=y; G[CNT].NEXT=H[X]; g[cnt].w=z;h[x]=cnt;} void read (int &num) {num=0;int F=1;char Ch=getchar (); while (ch< '! ') Ch=getchar (); if (ch== '-') F=-1,ch=getchar (); while (ch>= ' 0 ' &&ch<= ' 9 ') num=num*10+ch-' 0 ', Ch=getchar (); Num*=f;} void Cmax (int &a,int b) {if (b>a) a=b;} void get_g (int u,int fa) {f[u]=0;w[u]=1;b[u]=black[u];for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (vis[v]| | V==FA) continue; Get_g (V,u); W[u]+=w[v];b[u]+=b[v];cmax (F[u],w[v]);} Cmax (F[u],sum-w[u]); if (f[g]>f[u]) G=u;} void DFS (int u,int fa) {w[u]=1;b[u]=black[u];for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (vis[v]| | V==FA) Continue;dfs (v,u); w[u]+=w[v];b[u]+=b[v];} return;} void Get_dis (int u,int f,int d,int dis) {if (d>tmp) tmp=d;if (Dep[d]<dis) dep[d]=dis;for (int i=h[u];i;i=g[i].next) { int V=g[i].to;if (vis[v]| | V==F) continue; Get_dis (V,U,D+BLACK[V],DIS+G[I].W);} return;} void Get_ans (int u) {int len=0,flag=black[u];for (int i=0;i<=b[u];++i) mx_dep[i]=-oo;mx_dep[0]=0;for (int i=1;i<= tot;++i) {int v=son[i];tmp=0;for (int j=0;j<=b[v];++j) Dep[j]=-oo; Get_dis (V,-1,black[v],fa[v]), int now=0,mx=-oo;for (int j=tmp;j>=0;--j) {if (k-flag-j<0) continue;while (now< =LEN&&NOW<=K-FLAG-J) {Mx=max (Mx,mx_dep[now]); now++;} Ans=max (ANS,DEP[J]+MX);} if (Tmp>len) len=tmp;for (int j=len;j>=0;--j) {Mx_dep[j]=max (mx_dep[j],dep[j]);}} return;} void Get_div (int u) {DFS (u,-1); vis[u]=true;tot=0;for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (vis[v]) Continue;son [++TOT]=V;FA[V]=G[I].W;} Sort (son+1,son+tot+1,cmp); Get_ans (U); for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (VIS[V]) continue;g=0;sum=w[v]; Get_g (v,-1); Get_div (g);} return;} int main () {int __size__=128<<20;char *__p__= (char*) malloc (__size__) +__size__;__asm__ ("Movl%0,%%esp\n":: "R" ( __p__)); Read (n); read (k); Read (m); for (int i=1;i<=m;++i) {read (u); black[u]=true;} for (int i=1;i<n;++i) {read (u); Read (v); Read (a); Add (u,v,a); add (v,u,a);} G=0;sum=n;f[0]=oo; Get_g (1,-1); Get_div (g);p rintf ("%d\n", ans); return 0;}
Codeforces Div1 C
A construction topic that asks you to assign a-Z letter to each point in the tree
Requires that if there are two nodes of the same letter, then the path between the two points must have a node of the letter is larger than the letters of the two nodes
Define A>b>c ...
In fact, the purpose of this problem impossible is to amuse you, there is no solution
My way of construction is to use the tree division, the structure of the tree divided into the LOGN layer, the first layer assigned a, the second level of B ...
It is not difficult to find the correctness of this assignment, since each layer is assigned a value that is smaller than the current number of subtrees trees, so the subtree is independent
Exactly satisfying the nature of tree Division and treatment
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include < algorithm>using namespace Std;const int oo=0x7fffffff/3;const int maxn=100010;int n,u,v;int h[maxn],cnt=0;struct Edge{int To,next;} G[maxn<<1];int g,sum;int F[maxn],w[maxn];char ans[maxn];bool vis[maxn];void Add (int x,int y) {++cnt; G[cnt].to=y; g[cnt].next=h[x];h[x]=cnt;} void read (int &num) {Num=0;char Ch=getchar (); while (ch< '! ') Ch=getchar (); while (ch>= ' 0 ' &&ch<= ' 9 ') num=num*10+ch-' 0 ', Ch=getchar ();} void Cmax (int &a,int b) {if (b>a) a=b;} void get_g (int u,int fa) {f[u]=0;w[u]=1;for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (vis[v]| | V==FA) continue; Get_g (V,u); W[u]+=w[v];cmax (F[u],w[v]);} Cmax (F[u],sum-w[u]); if (F[g]>f[u]) g=u;} void DFS (int u,int f) {w[u]=1;for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (vis[v]| | V==F) Continue;dfs (v,u); w[u]+=w[v];} return;} void Get_div (int u,int d) {Vis[u]=true;dfs (u,-1); ans[u]=d+ ' A '; for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (vis[v]) Continue;g=0;sum=w[v]; Get_g (v,-1); Get_div (g,d+1);} return;} int main () {read (n); for (int i=1;i<n;++i) {read (u); Read (v); add (u,v); add (v,u);} F[0]=oo;g=0;sum=n; Get_g (1,-1); Get_div (g,0), for (int i=1;i<=n;++i) {Putchar (ans[i]), if (i==n) printf ("\ n"), Else printf (""); return 0;}
Uva Live 7148
Given a tree, each point has a bit of power
Ask you to ask for a monotonous non-descending path on the tree, and the difference between the maximum and minimum values is not greater than D
The maximum length of the output path
Would have wanted to forcibly write O (Nlogn), struggled for a while and did not write it out
Have to write O (nlog^2n), the process of tree division to maintain a tree segment after the discussion can be
Every time full query a subtrees tree, insert a subtrees tree in full
The segment tree takes the weight value as the key value and retains the maximum length of the current weight.
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include < algorithm>using namespace Std;const int maxn=100010;const int oo=0x7fffffff/3;int t,n,m,d,ans,mx;int u,v,kase,now; int c[maxn];int h[maxn],cnt=0;struct edge{int to,next;} G[maxn<<1];int g,sum,tim;bool vis[maxn];int f[maxn],w[maxn];int mx[maxn<<2];int t[maxn<<2];void Add (int x,int y) {++cnt; G[cnt].to=y; g[cnt].next=h[x];h[x]=cnt;} void read (int &num) {Num=0;char Ch=getchar (); while (ch< '! ') Ch=getchar (); while (ch>= ' 0 ' &&ch<= ' 9 ') num=num*10+ch-' 0 ', Ch=getchar ();} void Cmax (int &a,int b) {if (b>a) a=b;} void UPD (int o,int l,int r,int P,int v) {if (l==r) {if (t[o]!=tim) {t[o]=tim; Mx[o]=v;} else Cmax (mx[o],v); return;} int mid= (L+R) >>1;int l= (o<<1), r= (l|1), if (P<=mid) upd (l,l,mid,p,v), Else upd (r,mid+1,r,p,v); t[o]=tim; int a= (T[l]==tim? mx[l]:0); int b= (T[r]==tim? mx[r]:0); Mx[o]=max (A, b);} int ask (int o,int l,int r,int x,int y) {if (T[o]!=tim) return 0;if (l>=x&&r<=y) return Mx[o];int mid= (l+r) >>1;if (Y<=mid) return Ask (O<<1,l,mid,x,y), else if (x> MID) return ask (O<<1|1,mid+1,r,x,y), else return Max (ask (O<<1,l,mid,x,y), ask (O<<1|1,mid+1,r,x,y)) ;} void get_g (int u,int fa) {f[u]=0;w[u]=1;for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (vis[v]| | V==FA) continue; Get_g (V,u); W[u]+=w[v];cmax (F[u],w[v]);} Cmax (F[u],sum-w[u]); if (F[g]>f[u]) g=u;} void DFS (int u,int f) {w[u]=1;for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (vis[v]| | V==F) Continue;dfs (v,u); w[u]+=w[v];} return;} void get_up (int u,int f,int d) {int tmp=ask (1,1,mx,max (c[u]-d,1), C[u]), Cmax (ans,tmp+d+1); for (int i=h[u];i;i=g[i].next ) {int v=g[i].to;if (v==f| | VIS[V]) continue;if (c[v]>=c[u]&&c[v]-now<=d) get_up (v,u,d+1);} return;} void Get_down (int u,int f,int d) {int tmp=ask (1,1,mx,c[u],min)); Mx,c[u]+d (Cmax); for (int ans,tmp+d+1]. Next) {int v=g[i].to;if (v==f| | VIS[V]) continue;if (c[v]<=c[u]&&now-c[v]<=d) Get_down (v,u,d+1);} return;} void Dfs_down (int u,int f,int d) {UPD (1,1,mx,c[u],d); for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (v==f| | VIS[V]) continue;if (c[v]<=c[u]&&now-c[v]<=d) Dfs_down (v,u,d+1);} return;} void dfs_up (int u,int f,int d) {UPD (1,1,mx,c[u],d); for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (v==f| | VIS[V]) continue;if (c[v]>=c[u]&&c[v]-now<=d) dfs_up (v,u,d+1);} return;} void Get_div (int u) {Vis[u]=true;dfs (u,-1); tim++;for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (vis[v]) continue;if ( C[v]>=c[u]&&c[v]-c[u]<=d) now=c[u],get_up (v,-1,1); if (C[v]<=c[u]&&c[u]-c[v]<=d) now=c [U],dfs_down (v,-1,1);} tim++;for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (vis[v]) continue;if (C[v]<=c[u]&&c[u]-c[v]<=d) Now=c[u],get_down (v,-1,1); if (C[v]>=c[u]&&c[v]-c[u]<=d) now=c[u],dfs_up (v,-1,1);} for (int i=h[u];i;i=g[i].next) {int v=g[i].to;if (VIS[V]) continue;g=0;sum=w[v]; Get_g (v,-1); Get_div (g);} return;} int main () {//freopen ("s.in", "R", stdin);//freopen ("S1.out", "w", stdout); reAD (T); while (t--) {read (n); read (D); mx=0;kase++;for (int i=1;i<=n;++i) read (C[i]), Mx=max (Mx,c[i]), memset (h,0, sizeof (h)); Cnt=0;memset (vis,false,sizeof (VIS)); for (int i=1;i<n;++i) {read (u); Read (v); add (u,v); add (v,u);} Ans=1;g=0;sum=n;f[0]=oo; Get_g (1,-1); Get_div (g);p rintf ("Case #%d:%d\n", Kase,ans);} return 0;}
The limpid A1486 tree
Given a tree, the tree has a bit of power, and each dot is either a black dot or a white point.
Find a path that passes at least k black dots, maximizing path XOR and
If there is no limit to k black dots, we can run on the trie directly.
Then we use the tree division to remove the K black point limit, the remaining problem is the bare trie qaq
The key is to have a black point limit when querying.
Seems to be able to use a durable trie?
My approach is to maintain an MX domain for trie nodes, which represents the maximum number of black dots for the leaf nodes that the subtree expands.
So that we can be greedy on the trie to judge on the Qaq
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include < algorithm>using namespace Std;const int oo=0x7fffffff/3;const int maxn=100010;int n,k,u,v,ans;int black[maxn],c[ Maxn];bool vis[maxn];int h[maxn],cnt=0;struct edge{int to,next;} G[maxn<<1];int g,tot,sum;int mx[5000010];int nxt[5000010][2];int f[maxn],w[maxn];void Add (int x,int y) {++cnt; G[cnt].to=y; g[cnt].next=h[x];h[x]=cnt;} void read (int &num) {Num=0;char Ch=getchar (); while (ch< '! ') Ch=getchar (); while (ch>= ' 0 ' &&ch<= ' 9 ') num=num*10+ch-' 0 ', Ch=getchar ();} void Cmax (int &a,int b) {if (b>a) a=b;} void get_g (int u,int fa) {f[u]=0;w[u]=1; for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (vis[v]| | V==FA) continue; Get_g (V,u); w[u]+=w[v]; Cmax (F[u],w[v]); }cmax (F[u],sum-w[u]); if (F[g]>f[u]) g=u;} void DFS (int u,int f) {w[u]=1; for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (vis[v]| | V==F) contInue; DFS (V,u); w[u]+=w[v]; }return;} int Newnode () {tot++;nxt[tot][0]=nxt[tot][1]=0; Mx[tot]=0;return tot;} void Insert (int num,int k) {int now=1; for (int i=31;i>=0;--i) {int id= (num>>i&1); if (!nxt[now][id]) nxt[now][id]=newnode (); Now=nxt[now][id];mx[now]=max (MX[NOW],K); }return;} int ask (int num,int k) {int now=1,l=nxt[now][1],r=nxt[now][0]; if (mx[l]<k&&mx[r]<k) return-1; int ans=0; for (int i=31;i>=0;--i) {int id= (num>>i&1); id^=1; if (nxt[now][id]&&mx[nxt[now][id]]>=k) {ans|= (1<<i); Now=nxt[now][id]; }else Now=nxt[now][id^1]; }return ans;} void Get_ans (int u,int f,int d,int b) {int tmp=ask (d,k-b); Ans=max (ans,tmp); for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (vis[v]| | V==F) continue; Get_ans (V,u,d^c[v],b+black[v]); }return;} void Get_insert (int u,int f,int d,int b) {insert (D,B); for (int i=h[u];i;I=g[i].next) {int v=g[i].to; if (vis[v]| | V==F) continue; Get_insert (V,u,d^c[v],b+black[v]); }return;} void Get_div (int u) {tot=1;nxt[tot][0]=nxt[tot][1]=0; Insert (0,0); if (black[u]>=k) Ans=max (Ans,c[u]); Vis[u]=true;dfs (u,-1); for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (Vis[v]) continue; Get_ans (V,-1,c[u]^c[v],black[v]+black[u]); Get_insert (V,-1,c[v],black[v]); } for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (Vis[v]) continue; G=0;SUM=W[V]; Get_g (v,-1); Get_div (g); }return;} int main () {read (n); read (k); for (int i=1;i<=n;++i) read (Black[i]); for (int i=1;i<=n;++i) read (C[i]); for (int i=1;i<n;++i) {read (u); Read (v); Add (u,v); add (V,u); }ans=-1; G=0;sum=n;f[0]=oo; Get_g (1,-1); Get_div (g); printf ("%d\n", ans); return 0;}
Tree division usually solves the problem of the tree path
A wide range of applications can be used to optimize the problem can also be used to count
There is also a part of the problem of partition of the tree using the nature of the center of gravity and the structure of the LOGN layer of tree Division
If you encounter tree path-related problems, you might want to try it out with a tree.
Tree Division seems to be compatible with a lot of data structures to maintain information?
Several topics to be completed:
Two trees divide and cure +fft
And the love of a bauhinia flower.
Some knowledge points of the pit:
Palindrome Related Exercises
Can be persisted trie
Summary on the review of tree division and treatment