HDU 3974 Assign the task (线段树)

修改一个点,实际上等价于同时修改一些点。而将一棵树深度遍历所得到的序列中,根节点相同的节点的标号刚好是相邻的。

根据这个性质,用dfs对每个节点重新编号,修改一个点就变成了修改一个连续的区间。本题就变成了区间修改单点查询的线段树问题。


代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
#include <vector>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

int a[50005*4];
int add[50005*4];
bool root[50005];
int N,M;
int st[50005];
int ed[50005];
int Hs[50005];
int Num=0;
vector<int> G[50005];

void dfs(int u){
	Num++;
	Hs[u]=Num;
	st[u]=Num;
	for(int i=0;i<G[u].size();i++){
		dfs(G[u][i]);
	}
	ed[u]=Num;
}

void pushdown(int rt){
	if(add[rt]!=-1){
		add[rt<<1]=add[rt];
		add[rt<<1|1]=add[rt];
		a[rt<<1]=a[rt<<1|1]=add[rt];
		add[rt]=-1;
	}
}


void update(int L,int R,int l,int r,int rt,int n){
	pushdown(rt);
	if(L<=l&&R>=r){
		add[rt]=n;
		a[rt]=n;
		return ;
	}
	int mid=(l+r)>>1;
	if(mid>=L) update(L,R,lson,n);
	if(mid<R) update(L,R,rson,n);
}

int query(int n,int l,int r,int rt){
	pushdown(rt);
	if(l==r){
		return a[rt];
	}
	int mid=(l+r)>>1;
	if(mid>=n) return query(n,lson);
	else return query(n,rson);
}


int main(){
	int T;
	int kase=1;
	scanf("%d",&T);
	while(T--){
		memset(a,-1,sizeof(a));
		memset(add,-1,sizeof(add));
		memset(root,0,sizeof(root));
		memset(Hs,0,sizeof(Hs));
		Num=0;
		scanf("%d",&N);
		for(int i=0;i<=N;i++){
			G[i].clear();
		}
		for(int i=0;i<N-1;i++){
			int u,v;
			scanf("%d%d",&u,&v);
			G[v].push_back(u);
			root[u]=1;
		}
		for(int i=1;i<=N;i++){
			if(!root[i]){
				dfs(i);
				break;
			}
		}
		scanf("%d",&M);
		printf("Case #%d:\n",kase++);
		for(int i=0;i<M;i++){
			char ist[2];
			int x,y;
			scanf("%s",ist);
			if(ist[0]=='C'){
				scanf("%d",&x);
				printf("%d\n",query(Hs[x],1,Num,1));
			}
			else{
				scanf("%d%d",&x,&y);
				update(st[x],ed[x],1,Num,1,y);
			}
		}
	}
	return 0;
}


你可能感兴趣的:(线段树)