description
vjudge
给定一棵(n)点的树,每个节点上有一个颜色,每次询问一个点的子树中与这个点距离不超过(d)的点的颜色有多少种。强制在线。
——本题面描述转载租酥雨的博客,版权所有,仿冒必究
data range
[sum n,sum mle 5 imes 10^5
]
solution
考虑线段树合并。
首先想到维护深度的线段树,处理出每个节点对应深度最前的颜色有多少个。
合并时可能会算重,如果直接维护不知道颜色的重复情况,
所以还要维护一棵颜色的线段树,记录每个颜色的最浅深度
因为这里的每一棵线段树都要用于查询,因此合并时不能向主席树那样直接指儿子,而要新建节点
复杂度(O(nlogn))
Code
#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cassert>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define FL "a"
#define fi first
#define se second
#define RG register
using namespace std;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-6;
const int mod=1e4;
const int N=4e5+10;
const int M=4e5+10;
const dd pi=acos(-1);
const int inf=2147483647;
const ll INFL=1e18+1;
const ll P=100000;
inline ll read(){
RG ll data=0,w=1;RG char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
return data*w;
}
inline void file(){
srand(time(NULL)+rand());
freopen(FL".in","r",stdin);
freopen(FL".out","w",stdout);
}
int n,m,c[N],ans;
int head[N],nxt[N<<1],to[N<<1],cnt;
inline void add(int u,int v){to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;}
int drt[N],ds[2][20*N],sz[20*N],dtot;
#define mid ((l+r)>>1)
void dinsert(int &i,int l,int r,int p,int v){//sum of colors
int x=++dtot;ds[0][x]=ds[0][i];ds[1][x]=ds[1][i];sz[x]=sz[i]+v;i=x;
if(l==r)return;
p<=mid?dinsert(ds[0][i],l,mid,p,v):dinsert(ds[1][i],mid+1,r,p,v);
}
int query(int i,int l,int r,int x,int y){
if(!i||x>y)return 0;if(x<=l&&r<=y)return sz[i];int v=0;
if(x<=mid)v=query(ds[0][i],l,mid,x,y);
if(mid<y)v+=query(ds[1][i],mid+1,r,x,y);
return v;
}
int dmerge(int a,int b){
if(!a||!b)return a|b;int c=++dtot;
ds[0][c]=dmerge(ds[0][a],ds[0][b]);
ds[1][c]=dmerge(ds[1][a],ds[1][b]);
sz[c]=sz[a]+sz[b];return c;
}
int crt[N],cs[2][20*N],mn[20*N],ctot;
void cinsert(int &i,int l,int r,int p,int v){//mindep of color
if(!i){i=++ctot;mn[i]=inf;cs[0][i]=cs[1][i]=0;}
mn[i]=min(mn[i],v);if(l==r)return;
p<=mid?cinsert(cs[0][i],l,mid,p,v):cinsert(cs[1][i],mid+1,r,p,v);
}
int cmerge(int a,int b,int l,int r,int u){
if(!a||!b)return a|b;int c=++ctot;
if(l==r){
dinsert(drt[u],1,n,max(mn[a],mn[b]),-1);
mn[c]=min(mn[a],mn[b]);cs[0][c]=cs[1][c]=0;
}
else{
cs[0][c]=cmerge(cs[0][a],cs[0][b],l,mid,u);
cs[1][c]=cmerge(cs[1][a],cs[1][b],mid+1,r,u);
mn[c]=min(mn[cs[0][c]],mn[cs[1][c]]);
}
return c;
}
int dep[N];
void dfs(int u){
for(RG int i=head[u];i;i=nxt[i]){
RG int v=to[i];dfs(v);
crt[u]=cmerge(crt[u],crt[v],1,n,u);
drt[u]=dmerge(drt[u],drt[v]);
}
}
int main()
{
int T=read();
while(T--){
n=read();m=read();
ans=ctot=dtot=cnt=0;dep[1]=1;mn[0]=inf;
for(RG int i=1;i<=n;i++)head[i]=crt[i]=drt[i]=0,c[i]=read();
for(RG int i=2,fa;i<=n;i++)fa=read(),add(fa,i),dep[i]=dep[fa]+1;
for(RG int i=1;i<=n;i++){
dinsert(drt[i],1,n,dep[i],1);
cinsert(crt[i],1,n,c[i],dep[i]);
}
dfs(1);
for(RG int i=1,u,d;i<=m;i++){
u=read()^ans;d=dep[u]+(read()^ans);
ans=query(drt[u],1,n,1,min(d,n));printf("%d
",ans);
}
}
return 0;
}