HDU-3974 Assign the task(多叉树DFS时间戳建线段树)

怎甘沉沦 提交于 2019-11-28 16:50:55

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

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个职员刚好组成一棵树。然后有M个操作。

当给一个职员x分配任务y时(即 T y),x及其下属及其下属的下属都会放下手头的工作去完成任务y。对于每次询问(即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 }

 

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!