首页 > 代码库 > BZOJ 4551: [Tjoi2016&Heoi2016]树

BZOJ 4551: [Tjoi2016&Heoi2016]树

 

4551: [Tjoi2016&Heoi2016]树

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 748  Solved: 394
[Submit][Status][Discuss]

Description

在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下
两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个
结点,可以打多次标记。)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖
先)你能帮帮他吗?

Input

输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v
有一条有向边接下来Q行,形如“opernum”oper为“C”时表示这是一个标记操作,oper为“Q”时表示这是一个询
问操作对于每次询问操作,1 ≤ N, Q ≤ 100000。

Output

输出一个正整数,表示结果

Sample Input

5 5
1 2
1 3
2 4
2 5
Q 2
C 2
Q 2
Q 5
Q 3

Sample Output

1
2
2
1

HINT

 

 新加数据9组(By HFLSyzx ),未重测--2016.8.2

 

Source

 
[Submit][Status][Discuss]

 

分析

先离线读入所有的操作,统计每个点的标记次数,用并查集构建每个点向上最近的标记点。倒序处理操作,如果是查询,直接输出并查集的答案即可;否则该点标记次数减1,如果刚好变成0,就把并查集连向其父亲结点。

 

代码

技术分享
 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int N = 200005;
 6 
 7 int n, m;
 8 
 9 int tot;
10 int hd[N];
11 int nt[N];
12 int to[N];
13 
14 int ope[N];
15 int num[N];
16 int cnt[N];
17 int ans[N];
18 
19 char oper[5];
20 
21 int fa[N], f[N];
22 
23 int find(int u)
24 {
25     return fa[u] == u ? u : fa[u] = find(fa[u]);
26 }
27 
28 void prework(int u, int fr)
29 {
30     f[u] = fr;
31     
32     if (cnt[u])
33         fa[u] = u;
34     else
35         fa[u] = find(fr);
36         
37     for (int i = hd[u]; ~i; i = nt[i])
38         if (to[i] != fr)prework(to[i], u);
39 }
40 
41 signed main(void)
42 {
43     scanf("%d%d", &n, &m);
44     
45     memset(hd, -1, sizeof(hd));
46     
47     for (int i = 1; i < n; ++i)
48     {
49         int x, y; scanf("%d%d", &x, &y);
50         
51         nt[tot] = hd[x]; to[tot] = y; hd[x] = tot++;
52         nt[tot] = hd[y]; to[tot] = x; hd[y] = tot++;
53     }
54     
55     ++cnt[1];
56     
57     for (int i = 1; i <= m; ++i)
58     {
59         scanf("%s%d", oper, num + i);
60         
61         if (oper[0] == C)
62             ope[i] = 1, ++cnt[num[i]];
63     }
64     
65     prework(1, 1);
66     
67     for (int i = m; i >= 1; --i)
68     {
69         if (ope[i])
70         {
71             --cnt[num[i]];
72             if (!cnt[num[i]])
73                 fa[num[i]] = find(f[num[i]]);
74         }
75         else
76             ans[i] = find(num[i]);
77     }
78     
79     for (int i = 1; i <= m; ++i)
80         if (!ope[i])printf("%d\n", ans[i]);
81 }
BZOJ_4551.cpp

 

@Author: YouSiki

BZOJ 4551: [Tjoi2016&Heoi2016]树