题面
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.
法一:直接模拟多叉树+线段树
首先,读者可以画个树,自行标号dfs序,体会下dfs序的特点
不难发现,对于任意子树所含的结点编号是连续的
且该子树所含结点最小编号就是根结点编号
然后这个dfs序就是我们解决这道题的关键所在
按题意直接建好多叉树,标好dfs序,然后你会发现其实操作蛮简单的
查询员工,变成一层层去找对应子树根结点
#include <cstdio> #include <set> #include <cstring> using namespace std; const int maxn = 50005; struct node{int dat, child, nxt, tag, boss, l, r;}tr[maxn]; int t, n, m, boss, tot, p[maxn], a, b; void build(int p) { tr[p].l = ++tot; for (int i = tr[p].child; i; i = tr[i].nxt)build(i); tr[p].r = tot; } inline void create(int Boss, int k) { tr[k].boss = Boss; tr[k].nxt = tr[Boss].child; tr[Boss].child = k; } inline void push(int p) { if (!tr[p].tag)return; for (int i = tr[p].child; i; i = tr[i].nxt) tr[i].dat = tr[i].tag = tr[p].tag; tr[p].tag = 0; } inline void update(int l, int r, int p) { if (l == p) { tr[p].dat = tr[p].tag = r; return; } push(p); for (int i = tr[p].child; i;i=tr[i].nxt) if (tr[i].l <= tr[l].l && tr[l].l <= tr[i].r) update(l, r, i); } inline int query(int x, int p) { if (x == p) return tr[p].dat?tr[p].dat:-1; push(p); for (int i = tr[p].child; i; i = tr[i].nxt) if (tr[i].l <= tr[x].l && tr[x].l <= tr[i].r) return query(x, i); } int main() { scanf("%d", &t); for (int k = 1; k <= t; ++k) { scanf("%d", &n); printf("Case #%d: ", k); memset(tr, 0, sizeof tr); for (int i = 1; i < n; ++i) { int a, b; scanf("%d%d", &a, &b); create(b, a); } for (int i = 1; i <= n; ++i)if (!tr[i].boss) { boss = i; break; } build(boss); scanf("%d", &m); for (int i = 1; i <= m; ++i) { char s[2]; scanf("%s%d", s, &a); if (s[0] == 'C')printf("%d ", query(a, boss)); else { scanf("%d", &b); update(a, b, boss); } } } }
法二:并查集+模拟
每次查询,直接往上早,如果boss任务更新时间比当前任务晚,则更新当前任务
#include <cstdio> using namespace std; struct node {int job, time;}a[50005]; int fa[50005], t, n, m, u, v, cnt; char c[2]; int main() { scanf("%d", &t); for (int cas = 1, cnt = 0; cas <= t; ++cas, cnt = 0) { scanf("%d",&n); for (int i = 1; i <= n; ++i) fa[i] = a[i].job = a[i].time = -1; for (int i = 1; i < n; ++i) scanf("%d%d",&u,&v), fa[u] = v; scanf("%d", &m); printf("Case #%d:", cas); while (m--) { int x; scanf("%s%d", c, x); if (c[0] == 'C') { int y = a[x].job, tmp = a[x].time; for (;x != -1;x=fa[x]) if (a[x].time > tmp) y = a[x].job, tmp = a[x].time; printf("%d ", &y); } else { int y; scanf("%d", &y); a[x].job = y, a[x].time = ++cnt; } } } return 0; }