hdu3974 (dfs序+线段树)

问题:有一家公司有N个员工(从1到N),公司里每个员工都有一个直接的老板(除了整个公司的领导)。如果你是某人的直接老板,那个人就是你的下属,他的所有下属也都是你的下属。如果你是没有人的老板,那么你就没有下属,没有直接老板的员工就是整个公司的领导,也就是说N个员工构成了一棵树。公司通常把一些任务分配给一些员工来完成,当一项任务分配给某个人时,他/她会把它分配给他/她的所有下属,换句话说,这个人和他/她的所有下属在同一时间接受了一项任务。此外,每当员工收到一个任务,他/她将停止当前任务(如果他/她有),并开始新的任务。在公司将某些任务分配给某个员工后,编写一个程序来帮助找出某个员工当前的任务。

输入:第一行包含单个正整数T(T<=10),表示测试用例的数量。对于每个测试用例:第一行包含一个整数N(N≤50,000),它是雇员的数目。下面的N-1行分别包含两个整数u和v,这意味着雇员v是雇员u的直接老板(1<=u,v<=N)。下一行包含一个整数M(M≤50,000)。下面的M行分别包含一条消息,“Cx”表示对员工x的当前任务的查询,“Tx y”表示公司将任务y分配给员工x。(1<=x<=N,0<=y<=10^9)

输出:对于每个测试用例,在第一行打印测试用例编号(以1开头),然后为每个查询输出相应的答案。
在这里插入图片描述
这道题作为刚接触dfs序+线段树是很好的例题。dfs序是什么,就是给你一个树,然后按照dfs的顺序标记他们,记录树上每个节点的是进入dfs的时间,和dfs结束的时间,用两个数组存储,比如依照样例画的这个树,(蓝色笔就是刚刚进入的时间,绿色笔就是结束的时间) 首先就是从根节点开始,进入3节点,在进入4节点,回退到三(此时三节点还没有结束,但是四节点结束了,所以四的结束时间就是3),继续走到1节点回溯到3节点(3节点已经结束),按照这个样子遍历整颗树。
为什么要进行dfs序?可以这么看,我们原本数据给的图可以是一棵完全没有规律的树,但是dfs序之后,这么认为,对于原本树节点所对应的dfs序进入和结束的时间(比如根节点2的开始时间是1,结束时间是5),这个区间就是完全覆盖了该节点本身和他所有的子树。换个角度就是,dfs序对树的节点重新编号,每个节点的进入dfs的时间(也就是区间左端点的数值),就是该节点新的编号,然后要修改某个节点的值,就会影响下面所有子树的值,那么就是对于dfs序所生成的这个区间要修改这个区间,要修改根节点2,那么就要修改dfs序后重新编号后的1,2,3,4,5编号的节点,要修改3节点,就要修改dfs序后2,3,4,节点的值,注意dfs序后已经算作对于树的节点重新编号。
知道了这个,我们在用到线段树上就可以做这个问题了,要查询就是查询dfs序进入该节点的时间的值(左端点),该左端点就是dfs序后新给该节点的编号。
修改就对这个节点所对于的一整个区间都进行修改。这就是线段树裸模板题了。
如果对于dfs序还有没懂可以随时来问,我会尽力解答的。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<stack>
#include<cstring>
using namespace std;
const long long max_ = 50000 + 500;
int n, head[max_], root[max_], xiann = 1, ru[max_], chu[max_], cnt = 0; 
	struct k
{
	int to, next;
}xian[max_*2];
void add_(int a, int b) {
	xian[xiann].to = b;
	xian[xiann].next = head[a];
	head[a] = xiann;
	xiann++;
	return;
}

void dfs(int now, int fa)
{
	ru[now] = ++cnt;
	for (int i = head[now]; i ; i = xian[i].next)
	{
		int xia = xian[i].to;
		if (xia == fa) continue;
		dfs(xia, now);
	}
	chu[now] = cnt;
}
struct v
{
	int lazy_ = -1, value;
} tree_[max_ * 4];

void pushdown(int x) {
	tree_[x * 2].lazy_ = tree_[x * 2 + 1].lazy_ = tree_[x * 2].value = tree_[x * 2 + 1].value= tree_[x].lazy_;
	tree_[x].lazy_ = -1;
}
void update(int L , int R , int aimL , int aimR, int node , int value) {
	if (L > aimR || R < aimL) return;
	if (L >= aimL && R <= aimR) {
		tree_[node].value = value;
		tree_[node].lazy_ = value;
		return;
	}
	int mid = (L + R) / 2, Ltree_ = node * 2, Rtree_ = node * 2 + 1;
	if (tree_[node].lazy_ != -1) pushdown(node);
	update(L, mid, aimL, aimR, Ltree_, value);
	update(mid+1, R, aimL, aimR, Rtree_, value);
}
int ask(int L, int R, int aimnode, int node) {
	if (L == R) {
		return tree_[node].value;
	}
	int mid = (L + R) / 2, Ltree_ = node * 2, Rtree_ = node * 2 + 1;
	if (tree_[node].lazy_ != -1) pushdown(node);
	if (mid >= aimnode) {
		ask(L, mid, aimnode, Ltree_);
	}
	else {
		ask(mid+1, R, aimnode, Rtree_);
	}

}
int main() {
	int T;
	cin >> T;
	for(int w = 1 ; w <= T ; w++)
	{
		cin >> n;
		for (int i = 0; i <= n * 4; i++) {
			tree_[i].lazy_ = tree_[i].value = -1;
		}
		for (int i = 1; i <= n - 1; i++)
		{
			int a, b;
			cin >> a >> b;
			add_(a, b); add_(b, a);
			root[a]++;
		}
		int gen;
		for (int i = 1; i <= n; i++) {
			if (root[i] == 0) {
				gen = i; break;
			}
		}
		dfs(gen,-1);
		/*for (int i = 1; i <= n; i++) {
			cout << ru[i] << " " << chu[i] << endl;
		}*/
		int m;
		cin >> m;
		printf_s("Case #%d:\n", w);
		for (int i = 1; i <= m; i++) {
			char ch;
			cin >> ch;
			if (ch == 'C') {
				int a;
				cin >> a;
				cout << ask(1, n, ru[a], 1) << endl;
			}
			else {
				int a, b;
				cin >> a >> b;
				update(1, n, ru[a], chu[a], 1, b);
			}
		}
		memset(ru, 0, sizeof(ru));
		memset(chu, 0, sizeof(chu)); memset(head, 0, sizeof(head)); memset(root, 0, sizeof(root));
		xiann = 1, cnt = 0;
	}
	return 0;
}
发布了32 篇原创文章 · 获赞 3 · 访问量 684

猜你喜欢

转载自blog.csdn.net/qq_43804974/article/details/99702328