HDU - 5709 Claris Loves Painting 线段树动态开点+合并

题目链接:https://cn.vjudge.net/problem/HDU-5709

题意:给定一棵n点的树,每个节点上有一个颜色,每次询问一个点的子树中与这个点距离不超过d的点的颜色有多少种

题解:

对于每个节点建两个线段树

t1[x]维护x的子树中,深度在[l,r]内的颜色的种数,同种颜色只算一次,且取深度最小的那个

t2[x]维护x的子树中,每种颜色的最小深度

从下向上合并,t1先直接合并,合并t2的时候,若出现一样的颜色,则保留深度较小的那个,则对应删除t1中深度较大的那个,查询时直接在对应的t1中求和即可,至于复杂度都说是O((n+m)logn),感觉常数应该很大,至于内存开多大,就看着给的限制开吧,看的别人大多数是开的1e7左右,主要就是看到这种n为1e5左右,给的时间还挺多的,就试一下。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
int t1[N],t2[N];
int f[N],c[N],d[N];
int rson[N*110],lson[N*110],val[N*110];
int tot;
int newnode()
{
	tot++;
	lson[tot]=0;
	rson[tot]=0;
	val[tot]=0;
	return tot;
}
int update(int pre,int l,int r,int pos,int v)
{
	int cur=newnode();
	val[cur]=val[pre]+v;
	lson[cur]=lson[pre];
	rson[cur]=rson[pre];
	if(l==r)return cur;
	int mid=(l+r)>>1;
	if(pos<=mid) lson[cur]=update(lson[pre],l,mid,pos,v);
	else rson[cur]=update(rson[pre],mid+1,r,pos,v);
	return cur;
}
int merge1(int x,int y,int l,int r)
{
	if(!x || !y) return x + y;
	int cur=newnode();
	val[cur]=val[x]+val[y];
	if(l==r)return cur;
	int mid=(r+l)>>1;
	lson[cur]=merge1(lson[x],lson[y],l,mid);
	rson[cur]=merge1(rson[x],rson[y],mid+1,r);
	return cur;
}
int merge2(int x,int y,int l,int r,int u)
{
	if(!x || !y) return x + y;
	int cur=newnode();
	if(l==r)
	{
		val[cur]=min(val[x],val[y]);
		if(val[x]<val[y])t1[u]=update(t1[u],1,n,val[y],-1);
		else t1[u]=update(t1[u],1,n,val[x],-1);
		return cur;
	}
	int mid=(r+l)>>1;
	lson[cur]=merge2(lson[x],lson[y],l,mid,u);
	rson[cur]=merge2(rson[x],rson[y],mid+1,r,u);
	return cur;
}
int query(int p,int l,int r,int rt)
{
	if(rt==0)return 0;
	if(r<=p) return val[rt];
	int mid=(r+l)>>1;
	int res=0;
	res+=query(p,l,mid,lson[rt]);
	if(p>mid)  res+=query(p,mid+1,r,rson[rt]);
	return res;
}
int main()
{
	int T,nn=1;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		tot=0;
		for(int i=1;i<=n;i++)scanf("%d",&c[i]);
		for(int i=2;i<=n;i++)scanf("%d",&f[i]);
		for(int i=1;i<=n;i++) d[i]=d[f[i]]+1;
		for(int i=1;i<=n;i++)
		{
			t1[i]=update(0,1,n,d[i],1);
			t2[i]=update(0,1,n,c[i],d[i]);
		}
		for(int i=n;i>1;i--)
		{
			t1[f[i]]=merge1(t1[f[i]],t1[i],1,n);
			t2[f[i]]=merge2(t2[f[i]],t2[i],1,n,f[i]);
		}
		int ans=0;
		int u,dep;
		while(m--)
		{
			scanf("%d%d",&u,&dep);
	//		cout<<ans<<"==\n";
			u^=ans;
			dep^=ans;
			printf("%d\n",ans=query(min(d[u]+dep,n),1,n,t1[u]));
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/89950007