题干:

There is a company that has N employees(numbered from 1 to N),every employee in the company has a immediate boss (except for the leader of whole company).If you are the immediate boss of someone,that person is your subordinate, and all his subordinates are your subordinates as well. If you are nobody's boss, then you have no subordinates,the employee who has no immediate boss is the leader of whole company.So it means the N employees form a tree. 

The company usually assigns some tasks to some employees to finish.When a task is assigned to someone,He/She will assigned it to all his/her subordinates.In other words,the person and all his/her subordinates received a task in the same time. Furthermore,whenever a employee received a task,he/she will stop the current task(if he/she has) and start the new one. 

Write a program that will help in figuring out some employee’s current task after the company assign some tasks to some employee.

Input

The first line contains a single positive integer T( T <= 10 ), indicates the number of test cases. 

For each test case: 

The first line contains an integer N (N ≤ 50,000) , which is the number of the employees. 

The following N - 1 lines each contain two integers u and v, which means the employee v is the immediate boss of employee u(1<=u,v<=N). 

The next line contains an integer M (M ≤ 50,000). 

The following M lines each contain a message which is either 

"C x" which means an inquiry for the current task of employee x 

or 

"T x y"which means the company assign task y to employee x. 

(1<=x<=N,0<=y<=10^9)

Output

For each test case, print the test case number (beginning with 1) in the first line and then for every inquiry, output the correspond answer per line.

Sample Input

1 
5 
4 3 
3 2 
1 3 
5 2 
5 
C 3 
T 2 1
 C 3 
T 3 2 
C 3

Sample Output

Case #1:
-1 
1 
2

题目大意:

先输入n个人,然后是n个人的关系(下属 上司),然后分配任务,每一个上司分到一个任务就把任务给他的所有下属做,即他的下属的任务都是这个任务,查询一个人该时刻做的任务。

解题报告:

可以建模一下:是给定一棵树,然后一种操作是指定一个点,这个点及这个点的的子树被染色,另一种操作是指定一个点,问这个点的颜色。dfs序的实质就是:通过dfs树将这棵树放在线段上,然后用线段树优化求解。因为是单点查询所以不需要pushup,因为是区间更新并且需要叶子结点的值,所以需要pushdown。

AC代码:

#include<bits/stdc++.h>

using namespace std;
const int MAX = 50000 + 5;
int n;
int cnt,id;
int head[MAX*2];
int q[MAX*4],in[MAX*4],out[MAX*4],rudu[MAX*4];
struct Edge {
	int to;
	int ne;
} e[MAX*4];//要乘2 吗? 
struct TREE {
	int l,r;
	int val;
	int laz;
} tree[MAX * 10];

void dfs(int x,int root) {
	q[++id] = x;
	in[x] = id;
	for(int i = head[x]; i!=-1; i = e[i].ne) {
		dfs(e[i].to,x);
	}
	out[x] = id;
}
void add(int u,int v) {
	 e[++cnt].to = v;
	 e[cnt].ne = head[u];
	 head[u] = cnt;
}
void build(int l,int r,int cur) {
	tree[cur].l = l;
	tree[cur].r = r;
	tree[cur].val = -1;
	tree[cur].laz = 0;//懒标记初始化成0 
	if(l == r) {
		return ;
	}
	int m = (l + r) /2;
	build(l,m,cur*2);
	build(m+1,r,cur*2+1);
}
void pushup(int cur) {
	if(tree[cur*2].val == tree[cur*2+1].val) tree[cur].val = tree[cur*2].val;
	else tree[cur].val = -2;//染色问题   通解?   但是此题是单点查询所以不需要pushup? 
} 
void pushdown(int cur) {
	if(tree[cur].laz == 0) return ;
	tree[cur*2].val =tree[cur*2].laz = tree[cur*2+1].laz = tree[cur*2+1].val = tree[cur].laz;
	tree[cur].laz = 0;
}
void update(int pl,int pr, int val,int cur) {
	if(pl <= tree[cur].l && pr >= tree[cur].r) {
		tree[cur].val = val;
		tree[cur].laz = val;
		return ;
	}
	pushdown(cur);
	if(pl <= tree[cur*2].r) update(pl,pr,val,2*cur);
	if(pr >= tree[cur*2+1].l) update(pl,pr,val,2*cur+1);
	//pushup(cur);
} 
int query(int tar,int cur) {
	if(tree[cur].l == tree[cur].r) {
		return tree[cur].val;
	}
	pushdown(cur);
	if(tar <= tree[cur*2].r) return query(tar,cur*2);
	else return query(tar,cur*2+1);
	//pushup(cur);
}
int main()
{
//	freopen("in.txt","r",stdin);
	int t;
	int m,iCase = 0;
	int u,v;
	char op[10];
	cin>>t;
	while(t--) {
		printf("Case #%d:\n",++iCase);
		cnt = id = 0;
		memset(head,-1,sizeof(head));
		memset(rudu,0,sizeof rudu);
		memset(e,0,sizeof(e));
		scanf("%d",&n);
		for(int i = 1; i<n; i++) {//读入n-1次 
			scanf("%d%d",&u,&v);
			add(v,u);
			rudu[u]++;
		}	
		int st =1;
		for(int i = 1; i<=n; i++) {
			if(rudu[i] == 0) {
				st = 	i;break;
			}
		}		
		dfs(st,0);
		build(1,n,1);
		scanf("%d",&m);
		while(m--) {
			scanf("%s",op);
			if(op[0] == 'C') {
				scanf("%d",&u);
				printf("%d\n",query(in[u],1));
			} 
			else {
				scanf("%d%d",&u,&v);//把以u为根节点的子树更改为v 
				update(in[u],out[u],v,1);
			}
		}
		
	}
	return 0 ;
}
//19:15 

总结:

   注意dfs序,必须从根节点开始,所以还需要找根节点!!!这里是用拓扑排序中入度的思想找的根节点。 

  【POJ - 3321】 Apple Tree这道题也是dfs序,但是没有找根节点,因为题目告诉你了1号节点是根节点.

本题的数组都是佛系开的,其实只是tree需要4倍,其他的都开MAX就够用。RE了一次是因为,发现dfs需要找根节点而不能直接用1号节点之后,加了rudu数组,但是rudu没有每次初始化,所以re了。。(话说不应该wa吗,搞不懂。。