Assign the task(hdu 3974)

来源:互联网 发布:产品过程矩阵 编辑:程序博客网 时间:2024/05/19 09:36

Assign the task

TimeLimit: 15000/5000 MS (Java/Others)    Memory Limit:32768/32768 K (Java/Others)
Total Submission(s): 3842    Accepted Submission(s): 1592

ProblemDescription

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

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

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

 

 

Input

The first line contains a single positiveinteger 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 theemployees.

The following N - 1 lines each contain two integers u and v, which means theemployee 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 casenumber (beginning with 1) in the first line and then for every inquiry, outputthe correspond answer per line.

 

 

SampleInput

1

5

4 3

3 2

1 3

5 2

5

C 3

T 2 1

C 3

T 3 2

C 3

 

 

SampleOutput

Case #1:

-1

1

2

 

题意

   公司里有从1到n共n个成员,除了董事长,每个人都有唯一一个直接上司。每个人都有若干下属,自己下属的下属仍然算作是自己的下属。当给某个成员分配工作时,该成员和其所有下属会立刻丢弃原来的工作,执行当前的工作。现在有两种操作(1)C x 查询成员x当前的工作内容(2)T x y为成员x分配新的任务y。对于每次查询操作输出相应的结果。

 

思路

   首先n名成员构成了一个树形结构,我们可以用类似邻接表的方式先把树建立好。不难想到这道题应该是用线段树的区间更新来实现,难点在于每个成员在线段树中对应的区间是什么,本题的精髓便是用dfs求出了每个结点在线段树中对应的左右区间,并用l,r两个数组记录下来以便更新使用,变量num相当于用来给所有结点重新编号并可以通过递归的状态转移求出每个结点对应的左右区间,非常巧妙。另外一个比较难理解的点就是在查询操作C x时应当查询线段树中的哪一个点?答案是l[x]点,因为l[x].lazy一定是x的当前任务,理由是num从1开始不断变大,l[x]是最左端点只会受自己和父亲结点的改变而改变,说的不太清楚因为我也不会严格的证明,在纸上画一个图就很好理解了。

 

代码

 

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<vector>using namespace std;const int maxn = 50500;#define node tree[id]#define lson tree[id*2]#define rson tree[id*2+1]int n, m, u, v, num;vector<int> employee[maxn];int parent[maxn];int l[maxn << 2], r[maxn << 2];//确定原来的树节点对应在线段树中的左右区间struct Tree {int left, right, lazy;}tree[maxn << 2];void pushdown(int id) {if (node.lazy != -1 && node.left != node.right) {lson.lazy = rson.lazy = node.lazy;node.lazy = -1;}}void build(int id, int le, int ri) {node.left = le;node.right = ri;node.lazy = -1;if (le == ri) return;int mid = (le + ri) >> 1;build(id * 2, le, mid);build(id * 2 + 1, mid + 1, ri);}int query(int id, int pos) {if (node.left == node.right) {return node.lazy;}pushdown(id);int mid = (node.left + node.right) >> 1;if (pos <= mid) query(id * 2, pos);else query(id * 2 + 1, pos);}void update(int id, int x, int y, int v) {if (node.left >= x && node.right <= y) {node.lazy = v;return;}pushdown(id);int mid = (node.left + node.right) >> 1;if (x <= mid) update(id * 2, x, y, v);if (y > mid) update(id * 2 + 1, x, y, v);}void init() {num = 0;memset(l, -1, sizeof(l));memset(r, -1, sizeof(r));memset(parent, -1, sizeof(parent));for (int i = 0; i <= n; i++) {employee[i].clear();}}void dfs(int v) {++num;//最关键的一个变量l[v] = num;for (int i = 0; i < employee[v].size(); i++) {int u = employee[v][i];dfs(u);}r[v] = num;//原来的树中结点v在线段树中对应区间[le[v], ri[v]]}int main() {int t, x, y;char op;scanf("%d", &t);for (int kase = 1; kase <= t; kase++) {scanf("%d", &n);init();for (int i = 1; i < n; i++) {scanf("%d%d", &u, &v);employee[v].push_back(u);//employee[v][u]表示u是v的下属parent[u] = v;//parent[u] = v表示u的直接老板是v}scanf("%d", &m);printf("Case #%d:\n", kase);for (int i = 1; i <= n; i++) {if (parent[i] == -1) {//从根结点开始搜索dfs(i);break;}}build(1, 1, num);while (m--) {scanf(" %c", &op);if ('C' == op) {scanf("%d", &x);int ans = query(1, l[x]);printf("%d\n", ans);}else if ('T' == op) {scanf("%d%d", &x, &y);update(1, l[x], r[x], y);}}}return 0;}

原创粉丝点击