HDU - 3974

仔细想一下就发现就是dfs序上建线段树进行维护。。

建出这棵树的dfs序。(上下级关系)

每个节点掌控的区间为这个节点所在的子树(包括自己),由于是dfs,同一子树的结点的dfs序一定是连续的,即dfs序连续区间。

修改一个点,会把他的所有子孙所在结点全部赋值成一个值。就变成了dfs序的区间更新。

查询一个点,就直接查询这个点的dfs序就行。

//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int M = 5e4+7;
#define ls o*2
#define rs o*2+1
#define pb push_back
int l[M],r[M];//每个点在线段树中影响的区间  一定连续,因为按dfs序建树 
int ds[M];//每个点的dfs序 
int fa[M];
int ru[M];
int head[M];
struct EDGE
{
	int to,next,val;
}edge[M];
int cnt;
void add(int x,int y)
{
	edge[++cnt].to=y;
//	edge[cnt].val=w;
	edge[cnt].next=head[x];
	head[x]=cnt;
}
int dnt;//dfs序变量 
int hi;//dfs深度 
int mh;//最大深度 
int size[M];
vector<int >vec[M];
void dfs(int x)//跑出每个点的dfs序--方便建线段树 
{
	hi++;
	size[x]=1;
	for(int i=head[x];i!=0;i=edge[i].next)//遍历x指向的点 
	{
		int to=edge[i].to;
		ds[to]=++dnt;
		vec[hi].pb(to);//每层的结点编号
		mh=max(mh,hi);
		dfs(to);
		size[x]+=size[to];
	}
	hi--;
}
int tag[M<<2],st[M<<2];
void pd(int o)
{
	if(tag[o]==0)return ;
	tag[ls]=tag[rs]=st[ls]=st[rs]=tag[o];
	tag[o]=0;
}
void bd(int o,int l,int r)
{
	tag[o]=0;st[o]=-1;
	if(l==r)
		return ;
	int m=(l+r)/2;
	bd(ls,l,m);
	bd(rs,m+1,r);
}
void up(int o,int l,int r,int x,int y,int d)
{
	if(x<=l&&r<=y)
	{
		st[o]=tag[o]=d;
		return ;
	}
	pd(o);
	int m=(l+r)/2;
	if(x<=m)up(ls,l,m,x,y,d);
	if(y>m)up(rs,m+1,r,x,y,d);
}
int qu(int o,int l,int r,int x)
{
	if(l==r)
	{
		return st[o];
	}
	pd(o);
	int m=(l+r)/2;
	if(x<=m)return qu(ls,l,m,x);
	return qu(rs,m+1,r,x); 
}
int main()
{
	int T;
	scanf("%d",&T);
	for(int t=1;t<=T;t++)
	{
		
		int n,u,v;
		scanf("%d",&n);
		//-- 
			for(int i=1;i<=n;i++)ru[i]=0,fa[i]=i;
			memset(head,0,sizeof(head));
			dnt=cnt=0;
		//--初始化 
		for(int i=1;i<n;i++)
		{
			scanf("%d%d",&u,&v);
			add(v,u);
			fa[u]=v;
			ru[u]++;//入度 
		}
		int root;
		for(int i=1;i<=n;i++)if(ru[i]==0)root=i;
		ds[root]=++dnt;//根节点掌控全局 
		dfs(root);
		size[root]=n;
		for(int i=1;i<=n;i++)
			l[i]=ds[i],r[i]=l[i]+size[i]-1;
		int sz=dnt;
		bd(1,1,sz);
		
	/*	for(int i=1;i<=sz;i++)
		{
			printf("+++  %d  %d  %d  %d\n",i,ds[i],l[i],r[i]);
		}*/
		int m;
		scanf("%d",&m);
		printf("Case #%d:\n",t);
		for(int i=1;i<=m;i++)
		{
			char ss[3];
			scanf("%s",ss);
			if(ss[0]=='C')
			{
				int x;
				scanf("%d",&x);
			//	printf("ds:%d--\n",ds[x]);
				printf("%d\n",qu(1,1,sz,ds[x]));//单点查询x对应的点 
			}
			else
			{
				int x,d;
				scanf("%d%d",&x,&d);
			//	printf("%d --  %d\n",l[x],r[x]);
				up(1,1,sz,l[x],r[x],d);//区间更新结点x管辖的区间 
			}
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值