[bzoj4771]七彩树

首先考虑没有深度限制,即对一颗子树求颜色数,那么可以用树上差分,根据dfs序,每个点和这个颜色在dfs中上一次出现点的lca-1,然后每个点再打上一个+1,然后求一颗子树内所有节点的标记和即为答案。

为了深度限制,因此可以以深度为时间建一棵可持久化线段树,然后查询(x,d)即查询第deep[x]+d层的以x为根的子树,同时过程中可以维护当前插入的节点中每一个颜色的set(根据dfs排序)来处理lca的加减。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 100001
  4 #define mid (l+r>>1)
  5 struct ji{
  6     int nex,to;
  7 }edge[N<<1];
  8 int E,V,t,n,m,x,y,k,sz[N],c[N],r[N],sh[N],head[N],out[N],in[N],df[N],ndf[N],f[N][21],ls[N*100],rs[N*100],tr[N*100];
  9 set<int>se[N];
 10 struct node{
 11     int d,id; 
 12 }a[N];
 13 bool cmp(node  x,node y){
 14     return x.d<y.d; 
 15 }
 16 void add(int x,int y){
 17     edge[E].nex=head[x];
 18     edge[E].to=y;
 19     head[x]=E++;
 20 }
 21 void dfs(int k,int s){
 22     sz[k]=1;
 23     sh[k]=s;
 24     ndf[df[k]=++df[0]]=k;
 25     in[k]=++x;
 26     for(int i=head[k];i!=-1;i=edge[i].nex){
 27         dfs(edge[i].to,s+1);
 28         sz[k]+=sz[edge[i].to];
 29     }
 30     out[k]=++x;
 31 }
 32 bool pd(int x,int y){
 33     return (in[x]<=in[y])&&(out[y]<=out[x]);
 34 }
 35 int lca(int x,int y){
 36     if (pd(x,y))return x;
 37     if (pd(y,x))return y;
 38     for(int j=20;j>=0;j--)
 39         if (!pd(f[x][j],y))x=f[x][j];
 40     return f[x][0];
 41 }
 42 void update(int k1,int &k2,int l,int r,int x,int y){
 43     if ((x<l)||(x>r)||(l>r))return;
 44     tr[k2=++V];  
 45     ls[k2]=rs[k2]=0; 
 46     if (l==r){
 47         tr[k2]=tr[k1]+y;
 48         return;
 49     }
 50     update(ls[k1],ls[k2]=ls[k1],l,mid,x,y);
 51     update(rs[k1],rs[k2]=rs[k1],mid+1,r,x,y);
 52     tr[k2]=tr[ls[k2]]+tr[rs[k2]];
 53 }
 54 int query(int k,int l,int r,int x,int y){
 55     if ((x>r)||(l>y)||(l>r))return 0;
 56     if ((x<=l)&&(r<=y))return tr[k];
 57     return query(ls[k],l,mid,x,y)+query(rs[k],mid+1,r,x,y);
 58 }
 59 int main(){
 60     scanf("%d",&t);
 61     while (t--){
 62         scanf("%d%d",&n,&m);
 63         for(int i=1;i<=n;i++)scanf("%d",&c[i]);
 64         memset(head,-1,sizeof(head));
 65         E=V=df[0]=0;
 66         memset(r,0,sizeof(r));  
 67         for(int i=2;i<=n;i++){
 68             scanf("%d",&x);
 69             add(f[i][0]=x,i);
 70         }
 71         dfs(1,1); 
 72         f[1][0]=1; 
 73         for(int j=1;j<=20;j++)
 74             for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
 75         for(int i=1;i<=n;i++) a[i].id=i,a[i].d=sh[i];  
 76         sort(a+1,a+n+1,cmp);
 77         for(int i=1;i<=n;i++)se[i].clear();
 78         for(int i=1;i<=n;i++){
 79             k=a[i].id;  
 80             update(r[sh[a[i-1].id]],r[sh[k]],1,n,df[k],1);
 81             x=y=0;
 82             set<int>::iterator it=se[c[k]].lower_bound(df[k]);
 83             if (it!=se[c[k]].end())x=ndf[*it];
 84             if (it!=se[c[k]].begin())y=ndf[*(--it)];
 85             if (x)update(r[sh[k]],r[sh[k]],1,n,df[lca(x,k)],-1);
 86             if (y)update(r[sh[k]],r[sh[k]],1,n,df[lca(y,k)],-1);
 87             if ((x)&&(y))update(r[sh[k]],r[sh[k]],1,n,df[lca(x,y)],1);
 88             se[c[k]].insert(df[k]);
 89         }
 90         k=0;
 91         for(int i=1;i<=n;i++) if(!r[i]) r[i]=r[i-1];  
 92         while (m--){
 93             scanf("%d%d",&x,&y);
 94             x^=k;
 95             y^=k;  
 96             y=min(y+sh[x],n);  
 97             printf("%d\n",k=query(r[y],1,n,df[x],df[x]+sz[x]-1));
 98         }
 99     }
100 }
View Code

 

转载于:https://www.cnblogs.com/PYWBKTDA/p/11249947.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值