题解:P12017 [NOISG 2025 Finals] 可达性
这题有点难度。
读完题发现我们似乎束手无策。因为情况很多。
我们观察一下,树上两个点
对于情况
对于情况
这时我们就可以考虑对树上两个点讨论。
考虑
我们对两个点的到达点数量讨论。
第一种情况:若
情况
相当于把两个连通块合并。
对于情况
此时
值得说明的是,以上方程的后面的
第二种情况:若
对于情况
此时:
情况
第三种情况:若
对于情况
由于对
情况
我们使用类似滚动数组的方法搞个数组
::::success[AC code:]
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3+5;
int n, g[N], l[N], sz[N], f[N][2 * N];
vector<int> e[N];
inline void dfs(int u, int fa) {
sz[u] = 1;
for (int v : e[u]) {
if (v == fa)
continue;
dfs(v, u);
if (l[u] == l[v]) {
for (int i = 0; i <= sz[u]; i++)
for (int j = 0; j <= sz[v]; j++)
g[i + j] |= (f[u][i] & f[v][j]);
if (f[v][l[v]])
for (int i = 0; i <= sz[u]; i++)
g[i] |= f[u][i];
}
else {
if (l[u] > l[v]) {
if (!f[v][l[v]]) {
puts("NO");
exit(0);
}
for (int i = 0; i <= sz[u]; i++) {
g[i + l[v]] |= f[u][i];
g[i] |= f[u][i];
}
}
else {
if (!f[v][l[v]] && !f[v][l[v] - l[u]]) {
puts("NO");
exit(0);
}
else {
for (int i = 0; i <= sz[u]; i++)
g[i] |= f[u][i];
}
}
}
sz[u] += sz[v];
for (int i = 0; i <= sz[u]; i++)
f[u][i] = g[i], g[i] = 0;
}
}
int main() {
ios::sync_with_stdio(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> l[i];
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
for (int i = 1; i <= n; i++)
f[i][1] = 1;
dfs(1, 0);
puts(f[1][l[1]] ? "YES" : "NO");
return 0;
}
::::