题目链接:https://cn.vjudge.net/problem/HDU-5709
题意:给定一棵n点的树,每个节点上有一个颜色,每次询问一个点的子树中与这个点距离不超过d的点的颜色有多少种
题解:
对于每个节点建两个线段树
t1[x]维护x的子树中,深度在[l,r]内的颜色的种数,同种颜色只算一次,且取深度最小的那个
t2[x]维护x的子树中,每种颜色的最小深度
从下向上合并,t1先直接合并,合并t2的时候,若出现一样的颜色,则保留深度较小的那个,则对应删除t1中深度较大的那个,查询时直接在对应的t1中求和即可,至于复杂度都说是O((n+m)logn),感觉常数应该很大,至于内存开多大,就看着给的限制开吧,看的别人大多数是开的1e7左右,主要就是看到这种n为1e5左右,给的时间还挺多的,就试一下。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
int t1[N],t2[N];
int f[N],c[N],d[N];
int rson[N*110],lson[N*110],val[N*110];
int tot;
int newnode()
{
tot++;
lson[tot]=0;
rson[tot]=0;
val[tot]=0;
return tot;
}
int update(int pre,int l,int r,int pos,int v)
{
int cur=newnode();
val[cur]=val[pre]+v;
lson[cur]=lson[pre];
rson[cur]=rson[pre];
if(l==r)return cur;
int mid=(l+r)>>1;
if(pos<=mid) lson[cur]=update(lson[pre],l,mid,pos,v);
else rson[cur]=update(rson[pre],mid+1,r,pos,v);
return cur;
}
int merge1(int x,int y,int l,int r)
{
if(!x || !y) return x + y;
int cur=newnode();
val[cur]=val[x]+val[y];
if(l==r)return cur;
int mid=(r+l)>>1;
lson[cur]=merge1(lson[x],lson[y],l,mid);
rson[cur]=merge1(rson[x],rson[y],mid+1,r);
return cur;
}
int merge2(int x,int y,int l,int r,int u)
{
if(!x || !y) return x + y;
int cur=newnode();
if(l==r)
{
val[cur]=min(val[x],val[y]);
if(val[x]<val[y])t1[u]=update(t1[u],1,n,val[y],-1);
else t1[u]=update(t1[u],1,n,val[x],-1);
return cur;
}
int mid=(r+l)>>1;
lson[cur]=merge2(lson[x],lson[y],l,mid,u);
rson[cur]=merge2(rson[x],rson[y],mid+1,r,u);
return cur;
}
int query(int p,int l,int r,int rt)
{
if(rt==0)return 0;
if(r<=p) return val[rt];
int mid=(r+l)>>1;
int res=0;
res+=query(p,l,mid,lson[rt]);
if(p>mid) res+=query(p,mid+1,r,rson[rt]);
return res;
}
int main()
{
int T,nn=1;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
tot=0;
for(int i=1;i<=n;i++)scanf("%d",&c[i]);
for(int i=2;i<=n;i++)scanf("%d",&f[i]);
for(int i=1;i<=n;i++) d[i]=d[f[i]]+1;
for(int i=1;i<=n;i++)
{
t1[i]=update(0,1,n,d[i],1);
t2[i]=update(0,1,n,c[i],d[i]);
}
for(int i=n;i>1;i--)
{
t1[f[i]]=merge1(t1[f[i]],t1[i],1,n);
t2[f[i]]=merge2(t2[f[i]],t2[i],1,n,f[i]);
}
int ans=0;
int u,dep;
while(m--)
{
scanf("%d%d",&u,&dep);
// cout<<ans<<"==\n";
u^=ans;
dep^=ans;
printf("%d\n",ans=query(min(d[u]+dep,n),1,n,t1[u]));
}
}
return 0;
}