http://acm.hdu.edu.cn/showproblem.php?pid=3974
Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Problem Description
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
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
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个职员刚好组成一棵树。然后有M个操作。
当给一个职员x分配任务y时(即 T x y),x及其下属及其下属的下属都会放下手头的工作去完成任务y。对于每次询问(即C x),程序输出职员x正在进行什么任务。
简而言之:给出一个有向多叉树,初始所有节点为-1.有两种操作,一种为(T,x,y),表示将x节点及其的所有子树中的节点变为y,另一种为(C,x),为求x节点的值。
题解:
这道题的难点就在于如何将题中的对应关系转化为线段树的模型,在于如何处理好多叉树和线段树间的映射关系。
线段树的本质就是对一整段连续区间进行操作。所以这道题的关键就在于清楚怎么将对多叉树的操作转化成对一整段连续区间的操作。
很明显该公司的所有员工间的关系可以用一颗多叉树来表示。然后从公司老板(也就是入度为0的点)出发,用dfs给这棵树打上时间戳,确定每个点的影响范围并记录下来。
根据新分配的id号码将其节点对应映射到线段树上面。这样分配任务就相当于更新一段连续的节点,查询任务相当于单点查询。
代码如下:
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <set> 10 #include <stack> 11 #include <map> 12 #include <math.h> 13 const int INF=0x3f3f3f3f; 14 typedef long long LL; 15 const int mod=1e9+7; 16 //const double PI=acos(-1); 17 const int maxn=1e5+10; 18 using namespace std; 19 //ios::sync_with_stdio(false); 20 // cin.tie(NULL); 21 22 struct Edge_node 23 { 24 int v; 25 int next; 26 }Edge[50005*2]; 27 28 struct SegTree_node 29 { 30 int l; 31 int r; 32 int num; 33 }SegTree[50005<<2]; 34 int n,m; 35 int cnt;//边的计数器,从0开始 36 int num;//线段树序号的计数器,从1开始 37 int head[50005]; 38 int vis[50005];//是否有上司,即入度为0 39 int st[50005];//开始遍历时的编号,同时作为线段树中的序号 40 int ed[50005];//遍历结束后的序号,表示该点在线段树中可以影响的最后一个序号(即上司) 41 42 void init()//初始化 43 { 44 cnt=0; 45 num=0; 46 memset(head,-1,sizeof(head)); 47 memset(st,0,sizeof(st)); 48 memset(ed,0,sizeof(ed)); 49 memset(Edge,0,sizeof(Edge)); 50 memset(vis,0,sizeof(vis)); 51 } 52 53 void add_edge(int u,int v) 54 { 55 Edge[cnt].v=v; 56 Edge[cnt].next=head[u]; 57 head[u]=cnt++; 58 } 59 60 void DFS(int u) 61 { 62 num++; 63 st[u]=num; 64 for(int i=head[u];i!=-1;i=Edge[i].next) 65 { 66 DFS(Edge[i].v); 67 } 68 ed[u]=num; 69 } 70 71 void PushDown(int rt) 72 { 73 if(SegTree[rt].num!=-1) 74 { 75 SegTree[rt<<1].num=SegTree[rt<<1|1].num=SegTree[rt].num; 76 SegTree[rt].num=-1; 77 } 78 } 79 80 void Build(int l,int r,int rt) 81 { 82 SegTree[rt].l=l; 83 SegTree[rt].r=r; 84 SegTree[rt].num=-1; 85 if(l==r) 86 return ; 87 int mid=(l+r)>>1; 88 Build(l,mid,rt<<1); 89 Build(mid+1,r,rt<<1|1); 90 } 91 92 void Update(int L,int R,int C,int rt) 93 { 94 int l=SegTree[rt].l; 95 int r=SegTree[rt].r; 96 if(L<=l&&R>=r) 97 { 98 SegTree[rt].num=C; 99 return ; 100 } 101 PushDown(rt); 102 int mid=(l+r)>>1; 103 if(L<=mid) 104 Update(L,R,C,rt<<1); 105 if(R>mid) 106 Update(L,R,C,rt<<1|1); 107 } 108 109 int Query(int L,int rt) 110 { 111 int l=SegTree[rt].l; 112 int r=SegTree[rt].r; 113 if(l==r) 114 return SegTree[rt].num; 115 PushDown(rt); 116 int mid=(l+r)>>1; 117 if(L<=mid) 118 Query(L,rt<<1); 119 else if(L>mid) 120 Query(L,rt<<1|1); 121 } 122 123 int main() 124 { 125 int T; 126 scanf("%d",&T); 127 for(int k=1;k<=T;k++) 128 { 129 printf("Case #%d:\n",k); 130 init(); 131 scanf("%d",&n); 132 for(int i=1;i<n;i++) 133 { 134 int u,v; 135 scanf("%d %d",&u,&v); 136 vis[u]=1; 137 add_edge(v,u); 138 } 139 for(int i=1;i<=n;i++) 140 { 141 if(!vis[i]) 142 { 143 DFS(i); 144 break; 145 } 146 } 147 Build(1,num,1); 148 scanf("%d",&m); 149 for(int i=1;i<=m;i++) 150 { 151 char c[5]; 152 int x; 153 scanf("%s %d",c,&x); 154 if(c[0]=='C') 155 { 156 printf("%d\n",Query(st[x],1)); 157 } 158 else if(c[0]=='T') 159 { 160 int t; 161 scanf("%d",&t); 162 //st[x]->ed[x]代表x及x的下属在线段树中的区间范围 163 Update(st[x],ed[x],t,1); 164 } 165 } 166 } 167 return 0; 168 }