题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4771
题目分析:一道很妙的题。
先简化问题:假设没有深度限制,问题就变成了一棵子树中本质不同的颜色个数。只要将DFS序搞出来,就变成了一段区间中不同的数的个数,这个直接用可持久化线段树就可以解决了。有深度限制怎么办呢?我们可不可以按深度顺序将这些点加入主席树呢?答案是不可以的。因为以深度为顺序来加的话,加入一个点有可能要更改多棵主席树的形态,这就变成了可持久化树套树。所以我们不能将原问题转化成序列型问题考虑,要用一种更加巧妙的方法。
假设所有节点的颜色都不相同,且没有深度限制,那么询问一个点的答案就是其子树大小。假设有2个,3个或4个相同颜色的点,询问时答案会有什么变化呢?
我们发现,假设有k个相同颜色的点,将其按时间戳排好序。先令所有点权值为1,然后在第i-1个点和第i个点的lca处权值-1(2<=i<=k)。查询某个点的答案,就是它的子树权值之和。
再考虑按深度插入所有点。假设要在某种颜色的第i个点和第i+1个点之间新插入一个相同颜色的点,就先将第i个点和第i+1个点的lca权值加回1,然后在新点和第i个点,第i+1个点的lca处权值-1,最后令新点的权值为1。
要查询某种颜色的点的前驱和后继,对每种颜色开一棵treap即可。用可持久化线段树存储插入不同深度的点之后的每个点的权值。至于LCA嘛,我试着写了写传说中跑得飞快的树剖lca,顺便复习了一下BFS做树剖。
(这题的代码写了我一个晚上,然后第二天又debug了一个中午,发现原因居然是多组数据令我队列的边界出了问题。我写对拍的时候一直固定用n=1000来对拍,n相同时那段代码就不会有错,导致我一直找不出错QAQ)
CODE:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=101000;
const int maxl=25;
const long long M1=998244553;
const long long M2=1000000007;
const long long M3=1333333331;
typedef long long LL;
struct Seg
{
int sum;
Seg *Lson,*Rson;
} tree[maxn*maxl<<2];
Seg *Seg_Root[maxn];
int Scur;
struct Tnode
{
int id,fix;
Tnode *lson,*rson;
} Treap[maxn];
Tnode *Root[maxn];
int Tcur;
LL seed;
struct edge
{
int obj;
edge *Next;
} e[maxn];
edge *head[maxn];
int cur;
int fa[maxn];
int dep[maxn];
int Size[maxn];
int Son[maxn];
int Top[maxn];
int dfsx[maxn];
int w[maxn];
int ed[maxn];
int que[maxn];
int tail;
int cnt[maxn];
int Rank[maxn];
int max_dep;
int col[maxn];
int t,n,m;
void Add(int x,int y)
{
cur++;
e[cur].obj=y;
e[cur].Next=head[x];
head[x]=e+cur;
}
void Bfs()
{
tail=1;
que[1]=1;
fa[1]=dep[1]=1;
for (int i=1; i<=n; i++)
{
int node=que[i];
for (edge *p=head[node]; p; p=p->Next)
{
int son=p->obj;
fa[son]=node;
dep[son]=dep[node]+1;
que[++tail]=son;
}
}
Size[0]=0;
for (int i=n; i>=2; i--)
{
int node=que[i];
Size[ fa[node] ]+=Size[node];
if ( Size[node]>Size[ Son[ fa[node] ] ] ) Son[ fa[node] ]=node;
}
Top[1]=dfsx[1]=w[1]=1;
ed[1]=n;
for (int i=1; i<=n; i++)
{
int node=que[i],son=Son[node],Time=w[node]+1;
if (!son) continue;
Top[son]=Top[node];
dfsx[Time]=son;
w[son]=Time;
Time+=Size[son];
ed[son]=Time-1;
for (edge *p=head[node]; p; p=p->Next)
{
son=p->obj;
if (son==Son[node]) continue;
Top[son]=son;
dfsx[Time]=son;
w[son]=Time;
Time+=Size[son];
ed[son]=Time-1;
}
}
}
Seg *New_seg()
{
Scur++;
tree[Scur].sum=0;
tree[Scur].Lson=tree[Scur].Rson=tree;
return tree+Scur;
}
int Rand()
{
seed=(seed*M1+M2)%M3;
return (int)seed;
}
Tnode *New_node(int node)
{
Tcur++;
Treap[Tcur].id=node;
Treap[Tcur].fix=Rand();
Treap[Tcur].lson=Treap[Tcur].rson=NULL;
return Treap+Tcur;
}
void Right_turn(Tnode *&P)
{
Tnode *W=P->lson;
P->lson=W->rson;
W->rson=P;
P=W;
}
void Left_turn(Tnode *&P)
{
Tnode *W=P->rson;
P->rson=W->lson;
W->lson=P;
P=W;
}
void Insert(Tnode *&P,int node)
{
if (!P) P=New_node(node);
else
if ( w[node]id] )
{
Insert(P->lson,node);
if ( P->lson->fixfix ) Right_turn(P);
}
else
{
Insert(P->rson,node);
if ( P->rson->fixfix ) Left_turn(P);
}
}
int Find_prev(Tnode *P,int node,int ans)
{
if (!P) return ans;
if ( w[P->id]return Find_prev(P->rson,node,P->id);
return Find_prev(P->lson,node,ans);
}
int Find_succ(Tnode *P,int node,int ans)
{
if (!P) return ans;
if ( w[node]id] ) return Find_succ(P->lson,node,P->id);
return Find_succ(P->rson,node,ans);
}
int Lca(int u,int v)
{
if (Top[u]==Top[v])
if (w[u]return u;
else return v;
if (dep[ Top[u] ]return Lca(fa[ Top[u] ],v);
}
void Update(Seg *root,int L,int R,int x,int v)
{
if (L==R)
{
root->sum+=v;
return;
}
int mid=(L+R)>>1;
Seg *y=New_seg();
if (x<=mid)
{
(*y)=*(root->Lson);
Update(y,L,mid,x,v);
root->Lson=y;
}
else
{
(*y)=*(root->Rson);
Update(y,mid+1,R,x,v);
root->Rson=y;
}
root->sum=root->Lson->sum+root->Rson->sum;
}
void Work(Seg *&x,int node,int v)
{
Seg *y=New_seg();
(*y)=(*x);
Update(y,1,n,w[node],v);
x=y;
}
int Query(Seg *root,int L,int R,int x,int y)
{
if ( yreturn 0;
if ( x<=L && R<=y ) return root->sum;
int mid=(L+R)>>1;
int vl=Query(root->Lson,L,mid,x,y);
int vr=Query(root->Rson,mid+1,R,x,y);
return (vl+vr);
}
int main()
{
freopen("4771.in","r",stdin);
freopen("4771.out","w",stdout);
scanf("%d",&t);
while (t--)
{
scanf("%d%d",&n,&m);
cur=-1;
for (int i=1; i<=n; i++)
scanf("%d",&col[i]),head[i]=NULL,Size[i]=1,Son[i]=0,Root[i]=NULL;
for (int i=2; i<=n; i++)
{
int f;
scanf("%d",&f);
Add(f,i);
}
Bfs();
max_dep=0;
for (int i=1; i<=n; i++) max_dep=max(max_dep,dep[i]);
for (int i=1; i<=max_dep; i++) cnt[i]=0;
for (int i=1; i<=n; i++) cnt[ dep[i] ]++;
for (int i=2; i<=max_dep; i++) cnt[i]+=cnt[i-1];
for (int i=1; i<=n; i++) Rank[ cnt[ dep[i] ]-- ]=i;
seed=fa[n];
Scur=Tcur=-1;
Seg_Root[0]=New_seg();
tail=0;
for (int i=1; i<=max_dep; i++)
{
Seg *x=Seg_Root[i-1];
while ( dep[ Rank[tail+1] ]<=i && tailint node=Rank[++tail];
Insert(Root[ col[node] ],node);
int Prev=Find_prev(Root[ col[node] ],node,0);
int Succ=Find_succ(Root[ col[node] ],node,0);
int lca;
if ( Prev && Succ ) lca=Lca(Prev,Succ),Work(x,lca,1);
if (Prev) lca=Lca(Prev,node),Work(x,lca,-1);
if (Succ) lca=Lca(node,Succ),Work(x,lca,-1);
Work(x,node,1);
}
Seg_Root[i]=x;
}
int ans=0;
for (int i=1; i<=m; i++)
{
int x,d;
scanf("%d%d",&x,&d);
x^=ans,d^=ans;
d+=dep[x];
d=min(d,max_dep);
ans=Query(Seg_Root[d],1,n,w[x],ed[x]);
printf("%d\n",ans);
}
}
return 0;
}