Hdu 3974——Assign the task dfs序+线段树

题目: link.
题意:

公司里有一堆人,然后对于每个人(除了公司老板)每个人都有上属和下属,他们恰好构成一棵树,每当把任务分给某个人时,若他有下属,则他的所有子树全部做这个任务,对于每次查询输出某个节点正在做什么任务。
输入有2种操作:
1、C x 输入x这个人在做的任务编号 如果没工作输出-1
2、T x y 让x和x的下属做编号为y的工作

思路:

先跑一边dfs序,每个节点记录一个in和out表示时间戳,对于每个人p,in[p]到out[p]这段区间就是p的下属,dfs序完了之后用线段树维护每个人的工作,比如一个人p的工作变为y,把y一直pushdown给p的下属,update的区间就是in[p]到out[p]。
第一次碰到dfs序的题,看了题解才理解这道题,很牛逼

代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <map>
#include <queue>
#include <vector>
#define ll long long
#define T int T;scanf("%d", &T);while(T--)
#define inf 0x7f7f7f7f
using namespace std;
const int maxn = 5e4+10;
struct node{
	ll sum;
	int l,r;
	ll lazy;
}tree[maxn<<2];
vector<int> g[maxn];
bool vis[maxn];
int in[maxn];
int out[maxn];
int n,m;
int cnt;
void init(){	
	memset(vis,false,sizeof(vis));
	for(int i = 0; i < n+5; i ++){
		g[i].clear();
	}
	cnt = 0;
}
void build(int l, int r, int index){
	tree[index].l = l;
	tree[index].r = r;
	tree[index].lazy = -1;	//初值都为-1
	if(l==r){
		tree[index].sum = -1;	//初值都为-1,表示没工作
		return;
	}
	int mid = (l+r)/2;
	build(l,mid,index*2);
	build(mid+1,r,index*2+1);
}
void pushdown(int index){
	if(tree[index].lazy==-1) return;	//如果没新的工作不用向下更新
	tree[index*2].lazy = tree[index].lazy;
	tree[index*2+1].lazy = tree[index].lazy;
	tree[index*2].sum = tree[index].lazy;
	tree[index*2+1].sum = tree[index].lazy;
	tree[index].lazy = -1;
}
void update(int l, int r,int w,int index){	//正常区间更新
	if(l<=tree[index].l && tree[index].r<=r){
		tree[index].lazy = w;
		tree[index].sum = w;
		return;
	}
	pushdown(index);
	int mid = (tree[index].l+tree[index].r)/2;
	if(l<=mid) update(l,r,w,index*2);
	if(r>mid) update(l,r,w,index*2+1);
}
void query(int p,int index){	//正常单点查询
	if(tree[index].l==tree[index].r){
		printf("%lld\n", tree[index].sum);	
		return;
	}
	pushdown(index);
	int mid = (tree[index].l+tree[index].r)/2;
	if(p<=mid) query(p,index*2);
	else query(p,index*2+1);
}
void dfs(int u){	//dfs序,记录时间戳 
	in[u] = ++cnt;	//in[] 记录u点第一个下属,即自己
	for(auto i : g[u]){
		dfs(i);
	}
	out[u] = cnt;	//out记录u的最后一个下属
}	
int main(){
	int tt = 1;
	T{
		scanf("%d", &n);
		init();
		build(1,n,1);
		for(int i = 1; i < n; i ++){
			int u,v;
			scanf("%d %d", &u, &v);
			g[v].push_back(u);	//u是v的下属
			vis[u] = true;	//有领导
		}
		for(int i = 1; i <= n; i ++){
			if(vis[i]==false){	//没领导,即根结点
				dfs(i);		
				break;	
			}
		}
		printf("Case #%d:\n", tt++);
		scanf("%d", &m);
		char c;
		int x,y;
		while(m--){
			cin >> c;
			if(c=='C'){
				scanf("%d", &x);
				query(in[x],1);	//查x这个人的工作
			}else{
				scanf("%d %d", &x, &y);
				update(in[x],out[x],y,1);  //更新x的所有下属,即in到out这个区间
			}
		}
	}

	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值