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;
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值