[BZOJ4771]七彩树(主席树)
https://blog.csdn.net/KsCla/article/details/78249148
用类似经典的链上区间颜色计数问题的做法,这个题可以看成是询问DFS在[L[x],R[x]]中,深度在[dep[x],dep[x]+d]中,上一个同色点在[0,L[x]-1]中的点的个数。这是个三维数点问题,如果不强制在线的话,可以离线解决一维,主席树解决两维。
强制在线的话,其实还有一个“离线”方法:在所有询问前就将所有答案全部算好。
考虑两个同色点,在不考虑深度的情况下,它们所贡献的点是它们到根的链的并。对于链并问题,往往用set维护dfs序,然后插入点时处理dfs序相邻的两项的信息(差分),可以通过线段树来支持动态差分。
现在考虑深度,按深度建主席树即可。
讲的并不清楚,具体还是看上面的题解吧。代码应该还是比较好理解的。
1 #include<set> 2 #include<cstdio> 3 #include<vector> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) 7 typedef long long ll; 8 using namespace std; 9 10 const int N=100010,M=10000010; 11 int T,n,m,u,v,cnt,ans,tim,nd,x,d,co[N],dep[N],h[N],to[N],nxt[N]; 12 int ls[M],rs[M],sm[M],fa[N][19],L[N],R[N],pos[N],rt[N]; 13 vector<int>a[N]; 14 set<int>c[N]; 15 16 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 17 18 void dfs(int x){ 19 rep(i,1,18) fa[x][i]=fa[fa[x][i-1]][i-1]; 20 dep[x]=dep[fa[x][0]]+1; L[x]=++tim; 21 pos[tim]=x; a[dep[x]].push_back(x); 22 For(i,x) dfs(k=to[i]); R[x]=tim; 23 } 24 25 int lca(int u,int v){ 26 if (dep[u]<dep[v]) swap(u,v); 27 int t=dep[u]-dep[v]; 28 for (int i=18; ~i; i--) if (t&(1<<i)) u=fa[u][i]; 29 if (u==v) return u; 30 for (int i=18; ~i; i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; 31 return fa[u][0]; 32 } 33 34 void ins(int &x,int y,int L,int R,int pos,int k){ 35 x=++nd; ls[x]=ls[y]; rs[x]=rs[y]; sm[x]=sm[y]+k; 36 if (L==R) return; 37 int mid=(L+R)>>1; 38 if (pos<=mid) ins(ls[x],ls[y],L,mid,pos,k); 39 else ins(rs[x],rs[y],mid+1,R,pos,k); 40 } 41 42 int que(int x,int y,int L,int R,int l,int r){ 43 if (!y) return 0; 44 if (L==l && r==R) return sm[y]-sm[x]; 45 int mid=(L+R)>>1; 46 if (r<=mid) return que(ls[x],ls[y],L,mid,l,r); 47 else if (l>mid) return que(rs[x],rs[y],mid+1,R,l,r); 48 else return que(ls[x],ls[y],L,mid,l,mid)+que(rs[x],rs[y],mid+1,R,mid+1,r); 49 } 50 51 int main(){ 52 freopen("bzoj4771.in","r",stdin); 53 freopen("bzoj4771.out","w",stdout); 54 for (scanf("%d",&T); T--; ){ 55 scanf("%d%d",&n,&m); 56 rep(i,1,n) h[i]=0; cnt=tim=ans=nd=0; 57 rep(i,1,n) scanf("%d",&co[i]); 58 rep(i,2,n) scanf("%d",&fa[i][0]),add(fa[i][0],i); 59 rep(i,1,n) a[i].clear(),c[co[i]].clear(); 60 dfs(1); 61 rep(i,1,n){ 62 rt[i]=rt[i-1]; int ed=a[i].size()-1; 63 rep(j,0,ed){ 64 int x=a[i][j]; ins(rt[i],rt[i],1,n,L[x],1); c[co[x]].insert(L[x]); 65 set<int>::iterator it=c[co[x]].find(L[x]); 66 int pre=0,suf=0; it++; 67 if (it!=c[co[x]].end()) suf=*it; it--; 68 if (it!=c[co[x]].begin()) it--,pre=*it; 69 if (pre && suf) ins(rt[i],rt[i],1,n,L[lca(pos[pre],pos[suf])],1); 70 if (pre) ins(rt[i],rt[i],1,n,L[lca(pos[pre],x)],-1); 71 if (suf) ins(rt[i],rt[i],1,n,L[lca(pos[suf],x)],-1); 72 } 73 } 74 while (m--){ 75 scanf("%d%d",&x,&d); x^=ans; d^=ans; 76 printf("%d\n",ans=que(rt[dep[x]-1],rt[dep[x]+d],1,n,L[x],R[x])); 77 } 78 } 79 return 0; 80 }