有一个$n$个点的树,每个点有一个颜色,每次询问$x$点子树内距离小于等于$d$的点的颜色个数,强制在线
超级妙的一道题
首先我们可以想想如果不强制在线我们可以怎么做
$Dsu$ $on$ $tree$!
首先把所有询问离线下来,然后用$vector$存下来每个点的询问
按照深度建一个线段树表示深度小于等于$i$的点颜色个数有多少,开一个数组$d_i$表示颜色$i$出现的最低深度是多少
很显然如果$d_i$都无法对答案产生贡献,那么子树内就不存在能对答案产生贡献的颜色$i$
然后我们暴力遍历轻儿子的时候,如果当先前点为颜色$i$且当前点的深度小于$d_i$,就可以更新$d_i$的值
然后从线段树中删除之前的$d_i$的贡献,假如新的$d_i$的贡献,最后查询线段树回答询问即可
如果在线做我们也是要建一个类似的线段树保证查询的复杂度,问题是我们该如何求出子树中每种颜色最低的深度
假如我们事先已经知道一个点$x$的所有子树内颜色的最低深度,那么我们就可以利用线段树合并把他们合起来
然后对于回答询问的线段树的修改与之前是一样的,所以我们开两颗权值线段树就可以做出来这道题了
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define M 100010 5 using namespace std; 6 int n,m,T,cnt,ans; 7 int fa[M],deep[M],c[M],rt1[M],rt2[M]; 8 int val[M<<7],ch[M<<7][2]; 9 int insert(int rt,int l,int r,int pos,int v) 10 { 11 int node=++cnt;val[node]=val[rt]+v; 12 if(l==r) return node; 13 int mid=(l+r)/2; 14 ch[node][0]=ch[rt][0],ch[node][1]=ch[rt][1]; 15 if(pos<=mid) ch[node][0]=insert(ch[rt][0],l,mid,pos,v); 16 else ch[node][1]=insert(ch[rt][1],mid+1,r,pos,v); 17 return node; 18 } 19 int merge1(int x,int y,int l,int r) 20 { 21 if(!x||!y) return x+y; 22 int node=++cnt;val[node]=val[x]+val[y]; 23 if(l==r) return node; 24 int mid=(l+r)/2; 25 ch[node][0]=merge1(ch[x][0],ch[y][0],l,mid); 26 ch[node][1]=merge1(ch[x][1],ch[y][1],mid+1,r); 27 return node; 28 } 29 int merge2(int x,int y,int l,int r,int id) 30 { 31 if(!x||!y) return x+y; 32 int node=++cnt; 33 if(l==r) 34 { 35 if(val[x]>val[y]) val[node]=val[y],rt1[id]=insert(rt1[id],1,n,val[x],-1); 36 else val[node]=val[x],rt1[id]=insert(rt1[id],1,n,val[y],-1); 37 return node; 38 } 39 int mid=(l+r)/2; 40 ch[node][0]=merge2(ch[x][0],ch[y][0],l,mid,id); 41 ch[node][1]=merge2(ch[x][1],ch[y][1],mid+1,r,id); 42 return node; 43 } 44 int query(int node,int l,int r,int l1,int r1) 45 { 46 if(!node) return 0; 47 if(l1==l&&r1==r) return val[node]; 48 int mid=(l+r)/2; 49 if(r1<=mid) return query(ch[node][0],l,mid,l1,r1); 50 else if(l1>mid) return query(ch[node][1],mid+1,r,l1,r1); 51 else return query(ch[node][0],l,mid,l1,mid)+query(ch[node][1],mid+1,r,mid+1,r1); 52 } 53 void work() 54 { 55 cnt=ans=0; 56 scanf("%d%d",&n,&m); 57 for(int i=1;i<=n;i++) scanf("%d",&c[i]); 58 for(int i=2;i<=n;i++) scanf("%d",&fa[i]); 59 for(int i=1;i<=n;i++) deep[i]=deep[fa[i]]+1; 60 for(int i=1;i<=n;i++) 61 { 62 rt1[i]=insert(0,1,n,deep[i],1); 63 rt2[i]=insert(0,1,n,c[i],deep[i]); 64 } 65 for(int i=n;i>=2;i--) 66 { 67 rt1[fa[i]]=merge1(rt1[fa[i]],rt1[i],1,n); 68 rt2[fa[i]]=merge2(rt2[fa[i]],rt2[i],1,n,fa[i]); 69 } 70 for(int i=1;i<=m;i++) 71 { 72 int x,d;scanf("%d%d",&x,&d); 73 x^=ans,d^=ans; 74 ans=query(rt1[x],1,n,deep[x],min(deep[x]+d,n)); 75 printf("%d ",ans); 76 } 77 } 78 int main() 79 { 80 scanf("%d",&T); 81 while(T--) work(); 82 return 0; 83 }