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

 

posted @ 2018-12-11 20:02  HocRiser  阅读(152)  评论(0编辑  收藏  举报