D. Sasha and a Walk in the City
Sasha wants to take a walk with his girlfriend in the city. The city consists of $n$ intersections, numbered from $1$ to $n$. Some of them are connected by roads, and from any intersection, there is exactly one simple path$^{\dagger}$ to any other intersection. In other words, the intersections and the roads between them form a tree.
Some of the intersections are considered dangerous. Since it is unsafe to walk alone in the city, Sasha does not want to visit three or more dangerous intersections during the walk.
Sasha calls a set of intersections good if the following condition is satisfied:
- If in the city only the intersections contained in this set are dangerous, then any simple path in the city contains no more than two dangerous intersections.
However, Sasha does not know which intersections are dangerous, so he is interested in the number of different good sets of intersections in the city. Since this number can be very large, output it modulo $998\,244\,353$.
$^{\dagger}$A simple path is a path that passes through each intersection at most once.
Input
Each test consists of multiple test cases. The first line contains a single integer $t$ ($1 \le t \le 10^4$) — the number of test cases. The description of the test cases follows.
The first line of each test case contains a single integer $n$ ($2 \le n \leq 3 \cdot 10^5$) — the number of intersections in the city.
The next $(n - 1)$ lines describe the roads. The $i$-th line contains two integers $u_i$ and $v_i$ ($1 \leq u_i, v_i \leq n$, $u_i \ne v_i$) — the numbers of the intersections connected by the $i$-th road.
It is guaranteed that these roads form a tree.
It is guaranteed that the sum of $n$ over all test cases does not exceed $3 \cdot 10^5$.
Output
For each test case, output a single integer — the number of good sets of intersections modulo $998\,244\,353$.
Example
input
4
3
1 3
3 2
4
3 4
2 3
3 1
5
1 2
3 4
5 1
2 3
4
1 2
2 3
3 4
output
7
12
16
11
Note
In the first test case, there are $2^3 = 8$ sets of intersections. All of them are good, except for the set $\{1, 2, 3\}$, because if intersections $1, 2$, and $3$ are dangerous, then the simple path $1 - 2 - 3$ contains $3$ dangerous intersections. Thus, there are $7$ good sets.
In the second test case, there are $2^4 = 16$ sets of intersections. Among them, the sets $\{1, 2, 3, 4\}$, $\{1, 2, 3\}$, $\{1, 3, 4\}$, $\{2, 3, 4\}$ are not good. Thus, there are a total of $12$ good sets. The city layout is shown below:
解题思路
在以 $u$ 为根节点的子树中,其子节点为 $v_i$,现在假设已经求得子树 $v_i$ 中合法点集的数量,考虑如何推出子树 $u$ 的合法点集的数量。对于子树 $u$ 中的两个不同节点 $x$ 与 $y$,如果来自同一个子树 $v_i$,则其简单路径仍是合法的,不会受到 $u$ 和其他子节点子树的影响。如果分别来自两个不同 $v_i$ 的子树,其简单路径必然经过最近公共祖先 $u$,此时为了保证路径是合法的,那么 $x$ 到 $u$ 的路径中最多有 $2$ 个被选择的点,$y$ 到 $u$ 的路径中最多有 $2$ 个被选择的点,并且 $x$ 到 $y$ 的路径中最多有 $2$ 个被选择的点。因此我们关心的是子树里每个节点到根节点的路径中,被选择的点最多的那条里有多少个。
定义 $f(u,0/1/2)$ 表示以 $u$ 为根的子树中,且 $u$ 到每个节点路径中最多有 $0/1/2$ 个被选择的点时,(子树内任意简单路径)合法点集的数量。
对于 $f(u,0)$,即子树 $u$ 内任何节点都不会被选,显然有 $f(u,0) = 1$。
对于 $f(u,1)$,如果不选 $u$,那么每个子树 $v_i$ 内的点到 $v_i$ 的路径中既可以有 $0$ 个或 $1$ 个被选择的点(都能保证经过 $u$ 的简单路径中被选择的点不超过 $2$ 个),那么方案数就是 $\left( \prod{f(v_i,0)+f(v_i,1)} \right) - 1$,减 $1$ 指减去均取 $f(v_i,0)$ 的情况,因为要保证到 $u$ 的路径中最多有 $1$ 个被选择的点。如果选 $u$,那么每个子树 $v_i$ 中不能再选择点,只有 $\prod{f(v_i,0)} = 1$ 种方案。因此 $f(u,1) = \prod{f(v_i,0)+f(v_i,1)} - 1 + 1$。
对于 $f(u,1)$,如果不选 $u$,那么必须恰好有一个子树 $v_i$ 是 $f(v_i,2)$ 的状态,方案数就是 $\sum{f(v_i,2)}$。如果选 $u$,也是必须恰好有一个子树 $v_i$ 是 $f(v_i,1)$ 的状态,方案数就是 $\sum{f(v_i,1)}$。因此 $f(u,2) = \sum{f(v_i,2)+f(v_i,1)}$。
AC 代码如下,时间复杂度为 $O(n)$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e5 + 10, M = N * 2, mod = 998244353;
int h[N], e[M], ne[M], idx;
int f[N][3];
void add(int u, int v) {
e[idx] = v, ne[idx] = h[u], h[u] = idx++;
}
void dfs(int u, int pre) {
f[u][0] = f[u][1] = 1;
f[u][2] = 0;
for (int i = h[u]; i != -1; i = ne[i]) {
if (e[i] != pre) {
dfs(e[i], u);
f[u][1] = 1ll * f[u][1] * (f[e[i]][0] + f[e[i]][1]) % mod;
f[u][2] = ((LL)f[u][2] + f[e[i]][2] + f[e[i]][1]) % mod;
}
}
}
void solve() {
int n;
scanf("%d", &n);
memset(h, -1, n + 10 << 2);
idx = 0;
for (int i = 0; i < n - 1; i++) {
int u, v;
scanf("%d %d", &u, &v);
add(u, v), add(v, u);
}
dfs(1, -1);
printf("%d\n", ((LL)f[1][0] + f[1][1] + f[1][2]) % mod);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
参考资料
codeforces round #926 (div2) F+A-D 思路分享:https://www.bilibili.com/video/BV1VH4y1a7DP/
标签:City,子树,Walk,int,路径,Sasha,test,intersections,city From: https://www.cnblogs.com/onlyblues/p/18017370