版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Love_mona/article/details/81290422
蒟蒻的垂死挣扎
我跟你讲,这题巨火无比。
这题求子树中深度不超过dep[u]+D的颜色种类数,甚至还十分过分的要求强制在线,然后我脑袋里浮现出了树套树套树.....就很绝望。但是仔细想想,运用之前主席树的套路,我们可以记录某种颜色深度最浅的位置,在这个位置上贡献答案。那么我们考虑记录一个Min数组表示每种颜色出现的最浅深度,每个点建一棵下标为深度的线段树记录颜色种数即可。然后我们还会发现,这个Min数组也是要对于每个点开的,所以也开线段树,都要合并。接下来考虑怎么减去重复的贡献,我们在合并Min的那棵线段树时,可以找到两边都有的点,那么直接在里面Modify减去贡献即可。
之前我问萝卜这个是不是两只log的,他说是,但是我总觉得不对,自己想想发现是一只。
时间复杂度的证明:
线段树合并的复杂度不用证明吧。。。总共 O(nlogn)
而在合并的时候,看似里面套了一个Modify两只log,实际上来说只有颜色相同才会Modify,意思就是说总共不会进行超过颜色种数次更新,所以总共的复杂度也是一只log
询问就是普通的线段树查询,一个log
总复杂度 O((n+m)logn) 不过基于两颗线段树的操作,常数巨大。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#define ll long long
#define MOD 1000000007
#define N 110000
#define RG register
using namespace std;
inline int read(){
RG int x=0,o=1; RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') o=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=((x<<3)+(x<<1))+ch-'0',ch=getchar();
return x*o;
}
int n,m,top,first[N],dep[N],col[N];
struct mona { int nxt,en; } s[N<<1];
inline void Insert(int x,int y) { s[++top]=(mona) { first[x],y },first[x]=top; }
struct SegTree {
int tot,ls[N*100],rs[N*100],w[N*100],root[N*100];
inline void Build(int l,int r,int &x,int pos,int val){
x=++tot,w[x]=val,ls[x]=rs[x]=0;
if(l==r) return ; int mid=(l+r)>>1;
if(pos<=mid) Build(l,mid,ls[x],pos,val);
else Build(mid+1,r,rs[x],pos,val);
}
inline void Modify(int l,int r,int &x,int y,int pos){
x=++tot,ls[x]=ls[y],rs[x]=rs[y],w[x]=w[y]-1; if(l==r) return ;
int mid=(l+r)>>1;
if(pos<=mid) Modify(l,mid,ls[x],ls[y],pos);
else Modify(mid+1,r,rs[x],rs[y],pos);
}
inline int Query(int l,int r,int now,int L,int R){
if(L>R) return 0; if(l>=L&&r<=R) return w[now];
int mid=(l+r)>>1,ans=0;
if(L<=mid) ans+=Query(l,mid,ls[now],L,R);
if(R>mid) ans+=Query(mid+1,r,rs[now],L,R);
return ans;
}
inline int Merge_D(int u,int v){
if(!u||!v) return u+v;
int t=++tot; w[t]=w[u]+w[v];
ls[t]=Merge_D(ls[u],ls[v]);
rs[t]=Merge_D(rs[u],rs[v]);
return t;
}
inline void clear() { for(RG int i=1;i<=tot;++i) ls[i]=rs[i]=root[i]=w[i]=0; }
} M,D;
inline int Merge_M(int u,int v,int l,int r,int rt){
if(!u||!v) return u+v; int t=++M.tot,mid=(l+r)>>1;
if(l==r&&M.w[u]&&M.w[v]){
int sum=min(M.w[u],M.w[v]); M.w[t]=sum;
D.Modify(1,n,D.root[rt],D.root[rt],M.w[u]+M.w[v]-sum);
}
M.ls[t]=Merge_M(M.ls[u],M.ls[v],l,mid,rt);
M.rs[t]=Merge_M(M.rs[u],M.rs[v],mid+1,r,rt);
return t;
}
inline void Dfs(int k,int Dep){
dep[k]=Dep,M.Build(1,n,M.root[k],col[k],Dep);
D.Build(1,n,D.root[k],Dep,1);
for(RG int i=first[k];i;i=s[i].nxt){
int en=s[i].en; Dfs(en,Dep+1);
D.root[k]=D.Merge_D(D.root[k],D.root[en]);
M.root[k]=Merge_M(M.root[k],M.root[en],1,n,k);
}
}
int main(){
RG int T=read();
while(T--){
D.tot=M.tot=top=0; RG int x,lst_ans=0;
for(RG int i=1;i<=n;++i) first[i]=0;
n=read(),m=read();
for(RG int i=1;i<=n;++i) col[i]=read();
for(RG int i=2;i<=n;++i) x=read(),Insert(x,i);
Dfs(1,1);
for(RG int i=1;i<=m;++i){
int x=read()^lst_ans,d=read()^lst_ans;
printf("%d\n",lst_ans=D.Query(1,n,D.root[x],dep[x],dep[x]+d));
}
}
}