给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点。每个节点都被染上了某一种颜色,其中第i个节
点的颜色为c[i]。如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色。定义depth[i]为i节点与根节点的距离
,为了方便起见,你可以认为树上相邻的两个点之间的距离为1。站在这棵色彩斑斓的树前面,你将面临m个问题。
每个问题包含两个整数x和d,表示询问x子树里且depth不超过depth[x]+d的所有点中出现了多少种本质不同的颜色
。请写一个程序,快速回答这些询问。
口胡里说了。
不考虑深度,把同颜色的点按dfn排序,每个点对应位置+1,两两相邻lca处-1。这显然是是对的。
考虑深度,我们可以按深度排序依次插入,建可持久化线段树,查询直接查。
加速代码可以考虑询问时访问到空节点就直接退出。
#include
#include
#include
#include
#define min(a,b) (a
#define max(a,b) (a>b?a:b)
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10,maxtot=14000000+10;
int dfn[maxn],b[maxn],c[maxn],h[maxn],go[maxn],next[maxn],size[maxn];
int f[maxn][20],d[maxn],zjy[maxn];
int tree[maxtot],left[maxtot],right[maxtot],root[maxn],sta[80];
int i,j,k,l,r,x,y,t,n,m,mx,top,tot,ans,ca;
bool czy;
struct set_cmp{
bool operator ()(const int &x,const int &y){
return dfn[x]multiset<int,set_cmp> s[maxn];
multiset<int,set_cmp>::iterator it;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void add(int x,int y){
go[++tot]=y;
next[tot]=h[x];
h[x]=tot;
}
void dfs(int x){
dfn[x]=++top;
size[x]=1;
int t=h[x];
while (t){
f[go[t]][0]=x;
d[go[t]]=d[x]+1;
dfs(go[t]);
size[x]+=size[go[t]];
t=next[t];
}
}
bool cmp(int x,int y){
return d[x]int lca(int x,int y){
if (d[x]if (d[x]!=d[y]){
int j=zjy[d[x]-d[y]];
while (j>=0){
if (d[f[x][j]]>=d[y]) x=f[x][j];
j--;
}
}
if (x==y) return x;
int j=zjy[d[x]];
while (j>=0){
if (f[x][j]!=f[y][j]){
x=f[x][j];
y=f[y][j];
}
j--;
}
return f[x][0];
}
int newnode(int x){
tot++;
tree[tot]=tree[x];
left[tot]=left[x];
right[tot]=right[x];
return tot;
}
void insert(int &x,int l,int r,int a,int b){
x=newnode(x);
if (l==r){
tree[x]+=b;
return;
}
int mid=(l+r)/2;
if (a<=mid) insert(left[x],l,mid,a,b);else insert(right[x],mid+1,r,a,b);
tree[x]=tree[left[x]]+tree[right[x]];
}
int query(int x,int l,int r,int a,int b){
if (!x) return 0;
if (l==a&&r==b) return tree[x];
int mid=(l+r)/2;
if (b<=mid) return query(left[x],l,mid,a,b);
else if (a>mid) return query(right[x],mid+1,r,a,b);
else return query(left[x],l,mid,a,mid)+query(right[x],mid+1,r,mid+1,b);
}
void write(int x){
if (!x){
putchar('0');
putchar('\n');
return;
}
top=0;
while (x){
sta[++top]=x%10;
x/=10;
}
while (top) putchar('0'+sta[top--]);
putchar('\n');
}
int main(){
freopen("paint.in","r",stdin);freopen("data.out","w",stdout);
//czy=1;
ca=read();
//ca=1;
while (ca--){
n=read();m=read();
fo(i,1,n) c[i]=read();
fo(i,1,n) s[i].clear();
fo(i,1,n) h[i]=0;
tot=0;
fo(i,2,n){
j=read();
add(j,i);
}
d[1]=1;
top=0;
dfs(1);
fo(i,1,n) zjy[i]=floor(log(i)/log(2));
fo(j,1,zjy[n])
fo(i,1,n)
f[i][j]=f[f[i][j-1]][j-1];
fo(i,1,n) b[i]=i;
sort(b+1,b+n+1,cmp);
mx=0;
fo(i,1,n) mx=max(mx,d[i]);
j=k=tot=0;
fo(l,1,mx){
j=k+1;
while (k1]]==l) k++;
root[l]=root[l-1];
fo(i,j,k){
t=b[i];
insert(root[l],1,n,dfn[t],1);
it=s[c[t]].lower_bound(t);
if (it==s[c[t]].end()&&it==s[c[t]].begin()){
s[c[t]].insert(t);
continue;
}
else if (it==s[c[t]].end()){
x=*(--it);
insert(root[l],1,n,dfn[lca(t,x)],-1);
}
else if (it==s[c[t]].begin()){
y=*it;
insert(root[l],1,n,dfn[lca(t,y)],-1);
}
else{
y=*it;
x=*(--it);
insert(root[l],1,n,dfn[lca(x,y)],1);
insert(root[l],1,n,dfn[lca(t,x)],-1);
insert(root[l],1,n,dfn[lca(t,y)],-1);
}
s[c[t]].insert(t);
}
}
ans=0;
fo(i,1,m){
x=read();y=read();
if (czy){
x^=ans;
y^=ans;
}
ans=query(root[min(d[x]+y,mx)],1,n,dfn[x],dfn[x]+size[x]-1);
write(ans);
}
}
}