1. 程式人生 > >[BZOJ4771]七彩樹(主席樹)

[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 }