E. Chain Queries
You are given a tree of $n$ vertices numbered from $1$ to $n$. Initially, all vertices are colored white or black.
You are asked to perform $q$ queries:
- "u" — toggle the color of vertex $u$ (if it was white, change it to black and vice versa).
After each query, you should answer whether all the black vertices form a chain. That is, there exist two black vertices such that the simple path between them passes through all the black vertices and only the black vertices. Specifically, if there is only one black vertex, they form a chain. If there are no black vertices, they do not form a chain.
Input
Each test contains multiple test cases. The first line contains the number of test cases $t$ ($1\leq t\leq 10^4$). The description of the test cases follows.
The first line of each test case contains two integers $n$ and $q$ ($1\leq n,q\leq 2\cdot 10^5$).
The second line of each test case contains $n$ integers $c_1,c_2,\ldots,c_n$ ($c_i \in \{ \mathtt{0}, \mathtt{1} \}$) — the initial color of the vertices. $c_i$ denotes the color of vertex $i$ where $\mathtt{0}$ denotes the color white, and $\mathtt{1}$ denotes the color black.
Then $n - 1$ lines follow, each line contains two integers $x_i$ and $y_i$ ($1 \le x_i,y_i \le n$), indicating an edge between vertices $x_i$ and $y_i$. It is guaranteed that these edges form a tree.
The following $q$ lines each contain an integer $u_i$ ($1 \le u_i \le n$), indicating the color of vertex $u_i$ needs to be toggled.
It is guaranteed that the sum of $n$ and $q$ over all test cases respectively does not exceed $2\cdot 10^5$.
Output
For each query, output "Yes" if the black vertices form a chain, and output "No" otherwise.
You can output "Yes" and "No" in any case (for example, strings "yEs", "yes", "Yes" and "YES" will be recognized as a positive response).
Examples
input
2
2 1
1 0
1 2
1
5 4
1 0 0 0 0
1 2
1 3
1 5
3 4
4
3
2
5
output
No
No
Yes
Yes
No
Note
In the second test case, the color of the vertices are as follows:
The initial tree:
The first query toggles the color of vertex $4$:
The second query toggles the color of vertex $3$:
The third query toggles the color of vertex $2$:
The fourth query toggles the color of vertex $5$:
解题思路
把节点 $1$ 固定为树根,并规定节点 $1$ 的父节点为始终是白色的节点 $0$。如果树中只存在一条由黑色节点构成的链,只可能是以下两种形式:
若左边的情况要成立,必然满足以下 $2$ 个条件:
- 每个节点最多只有一个黑色儿子。
- 在所有的黑色节点中,有且只有一个黑色节点的父节点是白色。
若右边的情况要成立,必然满足以下 $2$ 个条件:
- 必然有一个黑色节点有恰好两个黑色儿子,其余节点最多只有一个黑色儿子。
- 在所有的黑色节点中,有且只有一个黑色节点的父节点是白色,且这个节点就是恰好两个黑色儿子的黑色节点。
为此我们维护以下信息。$p_u$ 表示节点 $u$ 的父节点;$s_u$ 表示节点 $u$ 黑色儿子的数量;$c_2$ 表示有恰好两个黑色儿子的节点数量;$c_3$ 表示有超过两个黑色儿子的节点数量;$f$ 表示在所有的黑色节点中父节点是白色的黑色节点数量;同时开一个 std::set
存储恰好两个黑色儿子的节点编号。考虑每次修改如何维护这些信息。
如果节点 $u$ 从黑色变白色:$u$ 的儿子会对 $f$ 有影响,有 $f \gets f + s_u$。$p_u$ 也对 $f$ 有影响,有 $f \gets f - [c_{p_u} = 0]$。$p_u$ 对 $s_{p_u}$,$c_2$,$c_3$ 有影响,为了方便用代码来表示:
if (s[p] == 2) c2--, st.erase(p);
else if (s[p] > 2) c3--;
s[p]--;
if (s[p] == 2) c2++, st.insert(p);
else if (s[p] > 2) c3++;
同理节点 $x$ 从白色变黑色,只需将一些加法操作改为减法,具体可见代码。
最后对于每个询问,如果以下条件有一个成立,都不会存在恰好一条由黑色节点构成的链,否则存在。
- 某个节点有 $3$ 个及以上的黑色儿子,即 $c_3 > 0$。
- 树中不存在黑色节点,或至少有两条链,即 $f \ne 1$。
- 有两个黑色儿子的节点不止一个,即 $c_2 > 1$。
- $c_2 = 1$,但这个节点不是黑色或这个节点的父节点不是白色。
AC 代码如下,时间复杂度为 $O(n+q)$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 5, M = N * 2;
int c[N];
int h[N], e[M], ne[M], idx;
int fa[N], s[N];
void add(int u, int v) {
e[idx] = v, ne[idx] = h[u], h[u] = idx++;
}
void dfs(int u, int p) {
fa[u] = p;
s[u] = 0;
for (int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if (v == p) continue;
s[u] += c[v];
dfs(v, u);
}
}
void solve() {
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", c + i);
}
idx = 0;
memset(h, -1, n + 1 << 2);
for (int i = 0; i < n - 1; i++) {
int u, v;
scanf("%d %d", &u, &v);
add(u, v), add(v, u);
}
dfs(1, 0);
int c2 = 0, c3 = 0, f = 0;
set<int> st;
for (int i = 1; i <= n; i++) {
if (s[i] == 2) c2++, st.insert(i);
else if (s[i] > 2) c3++;
if (c[i] && !c[fa[i]]) f++;
}
while (m--) {
int x;
scanf("%d", &x);
if (c[x]) {
f += s[x];
int p = fa[x];
if (!c[p]) f--;
if (p) {
if (s[p] == 2) c2--, st.erase(p);
else if (s[p] > 2) c3--;
s[p]--;
if (s[p] == 2) c2++, st.insert(p);
else if (s[p] > 2) c3++;
}
}
else {
f -= s[x];
int p = fa[x];
if (!c[p]) f++;
if (p) {
if (s[p] == 2) c2--, st.erase(p);
else if (s[p] > 2) c3--;
s[p]++;
if (s[p] == 2) c2++, st.insert(p);
else if (s[p] > 2) c3++;
}
}
c[x] ^= 1;
if (c3 || f != 1 || c2 > 1 || c2 == 1 && c[fa[*st.begin()]]) printf("NO\n");
else printf("YES\n");
}
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
参考资料
Codeforces Round #947 Editorial:https://codeforces.com/blog/entry/129801
标签:黑色,Chain,int,++,--,Queries,节点,color From: https://www.cnblogs.com/onlyblues/p/18221108