HDU 3974 Assign the task

Assign the task

Problem Description
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-1个关系将n个人构成一棵关系树,给某个人分配任务,这个人会将自己当前的任务分配给他的所有属下。给定m次操作,一种操作是询问x员工的当前任务,另一种操作是给x员工分配y任务。
思路:由于现在是一棵关系树,我们可以将按子节点的个数划分区间,对于某个节点,从根节点遍历到当前节点的num数为该节点的左区间,遍历完当前节点所有子节点之后的num为该节点的右区间,那么当前的区间就包含了当前节点的所有子节点。 我觉得难点就是在这里吧!根据树划分区间,之后的都是线段树的基本操作了
 
  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 
  6 using namespace std;
  7 const int maxn = 50005;
  8 struct node{
  9     int to,next;
 10 }e[maxn];
 11 int a[maxn<<2],add[maxn<<2];
 12 int f[maxn],head[maxn];
 13 int ls[maxn],rs[maxn];
 14 int n,m,T,cnt,num;
 15 void ade(int u,int v)//加边 便于dfs搜索
 16 {
 17     e[cnt].to = u;
 18     e[cnt].next = head[v];
 19     head[v] = cnt++;
 20 }
 21 int Find(int x){//并查集
 22     if(x!=f[x])
 23         f[x] = Find(f[x]);
 24     return f[x];
 25 }
 26 void dfs(int rt)//求出当前节点覆盖的区间左值和右值
 27 {
 28     int x = head[rt];
 29     ls[rt] = ++num;
 30     while(x!=-1){
 31         dfs(e[x].to);
 32         x = e[x].next;
 33     }
 34     rs[rt] = num;
 35 }
 36 void pushdown(int rt)
 37 {
 38     if(add[rt]){
 39         a[rt<<1] = a[rt];
 40         a[rt<<1|1] = a[rt];
 41         add[rt<<1] = add[rt];
 42         add[rt<<1|1] = add[rt];
 43         add[rt] = 0;
 44     }
 45 }
 46 void build(int l,int r,int rt)
 47 {
 48     a[rt] = -1;//
 49     add[rt] = 0;//此处初始化所有点线段树节点都为-1和0;
 50     if(l==r)return;
 51     int mid = (l+r)>>1;
 52     build(l,mid,rt<<1);
 53     build(mid+1,r,rt<<1|1);
 54 }
 55 void update(int L,int R,int C,int l,int r,int rt)
 56 {
 57     if(L<=l&&r<=R){
 58         a[rt] = C;
 59         add[rt] = C;
 60         return;
 61     }
 62     pushdown(rt);//下推懒惰标记
 63     int mid = (l+r)>>1;
 64     if(L<=mid)update(L,R,C,l,mid,rt<<1);
 65     if(R>mid)update(L,R,C,mid+1,r,rt<<1|1);
 66 }
 67 int query(int L,int R,int l,int r,int rt)
 68 {
 69     if(L<=l&&r<=R)return a[rt];
 70     pushdown(rt);//下推懒惰标记
 71     int mid = (l+r)>>1;
 72     int ans = 0;
 73     if(L<=mid) ans += query(L,R,l,mid,rt<<1);
 74     if(R>mid) ans += query(L,R,mid+1,r,rt<<1|1);
 75     return ans;
 76 }
 77 int main()
 78 {
 79     scanf("%d",&T);
 80     for(int t=1;t<=T;t++){
 81         scanf("%d",&n);
 82         cnt = 0,num = 0;
 83         for(int i=0;i<=n;i++){
 84             f[i]=i;head[i]=-1;
 85             ls[i]=0,rs[i]=0;
 86         }
 87         for(int l,r,i=1;i<n;i++){
 88             scanf("%d%d",&l,&r);
 89             f[l]=r;
 90             ade(l,r);
 91         }
 92         int root = Find(1);//利用并查集的思想求出根节点
 93         dfs(root);//根据根节点 求出每个节点覆盖的区间 区间左值在ls中,右值在rs中
 94 //        cout<<ls[root]<<" "<<rs[root]<<endl;
 95 //        for(int i=1;i<=n;i++)
 96 //            cout<<ls[i]<<" "<<rs[i]<<endl;
 97 //        getchar();
 98         build(1,n,1);
 99         scanf("%d",&m);
100         char op;int x,y;
101         printf("Case #%d:\n",t);
102         while(m--){
103             scanf(" %c",&op);
104             if(op=='C'){
105                 scanf("%d",&x);
106                 printf("%d\n",query(ls[x],ls[x],1,n,1));//区间的单点查询
107             }else if(op=='T'){
108                 scanf("%d%d",&x,&y);
109                 update(ls[x],rs[x],y,1,n,1);//区间更新当前的任务
110             }
111         }
112     }
113     return 0;
114 }

猜你喜欢

转载自www.cnblogs.com/wangrunhu/p/9641575.html