1. 程式人生 > >【BZOJ4771】七彩樹 主席樹+樹鏈的並

【BZOJ4771】七彩樹 主席樹+樹鏈的並

iter 有一個 inpu ont 實的 print algorithm 包含 char

【BZOJ4771】七彩樹

Description

給定一棵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的所有點中出現了多少種本質不同的顏色。請寫一個程序,快速回答這些詢問。

Input

第一行包含一個正整數T(1<=T<=500),表示測試數據的組數。 每組數據中,第一行包含兩個正整數n(1<=n<=100000)和m(1<=m<=100000),表示節點數和詢問數。 第二行包含n個正整數,其中第i個數為c[i](1<=c[i]<=n),分別表示每個節點的顏色。 第三行包含n-1個正整數,其中第i個數為f[i+1](1<=f[i]<i),表示節點i+1的父親節點的編號。 接下來m行,每行兩個整數x(1<=x<=n)和d(0<=d<n),依次表示每個詢問。 輸入數據經過了加密,對於每個詢問,如果你讀入了x和d,那麽真實的x和d分別是x xor last和d xor last, 其中last表示這組數據中上一次詢問的答案,如果這是當前數據的第一組詢問,那麽last=0。 輸入數據保證n和m的總和不超過500000。

Output

對於每個詢問輸出一行一個整數,即答案。

Sample Input

1
5 8
1 3 3 2 2
1 1 3 3
1 0
0 0
3 0
1 3
2 1
2 0
6 2
4 1

Sample Output

1
2
3
1
1
2
1
1

題解:先不考慮深度的限制。我們分別考慮每種顏色。

如果這個顏色只有一個點,那麽它對它的所有祖先的貢獻都是1,如果有2個點a,b,那麽它們對a和b的祖先貢獻都是1,其中兩者lca的祖先被重復計算了1次,要將它減去。

以此類推,這些點對它們的樹鏈的並的貢獻都是1,所以求出樹鏈的並,用線段樹維護子樹權值和即可。

但是如果考慮深度限制呢?將線段樹改成主席樹即可,即對於每個深度都維護一棵線段樹。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
const int maxn=100010;
int n,m,cnt,tot,ans;
set<int> S[maxn];
set<int>::iterator it;
int to[maxn],next[maxn],head[maxn],fa[19][maxn],dep[maxn],Log[maxn],p[maxn],q[maxn],pd[maxn],Q[maxn],rt[maxn],v[maxn];
struct node
{
	int ls,rs,siz;
}s[maxn*50];
void dfs(int x)
{
	p[x]=++q[0],Q[q[0]]=x;
	for(int i=head[x];i!=-1;i=next[i])	dep[to[i]]=dep[x]+1,dfs(to[i]);
	q[x]=q[0];
}
inline int lca(int a,int b)
{
	if(dep[a]<dep[b])	swap(a,b);
	for(int i=Log[dep[a]-dep[b]];i>=0;i--)	if(dep[fa[i][a]]>=dep[b])	a=fa[i][a];
	if(a==b)	return a;
	for(int i=Log[dep[a]];i>=0;i--)	if(fa[i][a]!=fa[i][b])	a=fa[i][a],b=fa[i][b];
	return fa[0][a];
}
bool cmp(int a,int b)
{
	return dep[a]<dep[b];
}
void insert(int x,int &y,int l,int r,int a,int b)
{
	y=++tot,s[y].ls=s[y].rs=s[y].siz=0;
	s[y].siz=s[x].siz+b;
	if(l==r)	return ;
	int mid=(l+r)>>1;
	if(a<=mid)	s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,a,b);
	else	s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,a,b);
}
int query(int l,int r,int x,int a,int b)
{
	if(!x||(a<=l&&r<=b))	return s[x].siz;
	int mid=(l+r)>>1;
	if(b<=mid)	return query(l,mid,s[x].ls,a,b);
	if(a>mid)	return query(mid+1,r,s[x].rs,a,b);
	return query(l,mid,s[x].ls,a,b)+query(mid+1,r,s[x].rs,a,b);
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
inline void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
void work()
{
	n=rd(),m=rd(),tot=cnt=ans=q[0]=0;
	int i,j,a,b;
	memset(head,-1,sizeof(head));
	memset(rt,0,sizeof(rt));
	memset(fa,0,sizeof(fa));
	for(i=1;i<=n;i++)	v[i]=rd(),S[i].clear(),pd[i]=i;
	for(i=2;i<=n;i++)	fa[0][i]=rd(),add(fa[0][i],i),Log[i]=Log[i>>1]+1;
	dep[1]=1,dfs(1);
	for(j=1;(1<<j)<=n;j++)	for(i=1;i<=n;i++)	fa[j][i]=fa[j-1][fa[j-1][i]];
	sort(pd+1,pd+n+1,cmp);
	for(i=1;i<=n;i++)
	{
		j=pd[i],a=b=0,it=S[v[j]].lower_bound(p[j]);
		insert(rt[dep[pd[i-1]]],rt[dep[j]],1,n,p[j],1);
		if(it!=S[v[j]].end())	b=Q[(*it)],insert(rt[dep[j]],rt[dep[j]],1,n,p[lca(b,j)],-1);
		if(it!=S[v[j]].begin())	it--,a=Q[(*it)],insert(rt[dep[j]],rt[dep[j]],1,n,p[lca(a,j)],-1);
		if(a&&b)	insert(rt[dep[j]],rt[dep[j]],1,n,p[lca(a,b)],1);
		S[v[j]].insert(p[j]);
	}
	for(i=1;i<=m;i++)
	{
		a=rd()^ans,b=rd()^ans;
		ans=query(1,n,rt[min(dep[a]+b,dep[pd[n]])],p[a],q[a]);
		printf("%d\n",ans);
		//ans=0;
	}
}
int main()
{
	int T=rd();
	while(T--)	work();
	return 0;
}//1 4 4 4 2 3 2  1 2 1  3 2 2 2 4 1 4 1 

【BZOJ4771】七彩樹 主席樹+樹鏈的並