题解:AT_agc008_f [AGC008F] Black Radius
posted on 2024-11-14 07:35:28 | under | source
蒟蒻看完题解后的一些理解。
先考虑每个点都可以选的情况,记 \(S(u,k)\) 表示所有与 \(u\) 的距离不超过 \(k\) 的点构成的连通块。
本题难点在于可能有 \(S(u,k)=S(u^\prime,k^\prime)\),导致算重。但是可以发现,除了整棵树的情况,对于一个连通块 \(S\),在所有 \(S(u,k)=S\) 中恰有唯一一个最小的 \(k\)。这不难证明,对于所有 \(S(u,k)=S\),那么两点 \(u\ne v\) 它们的 \(k\) 必然不同。
把整棵树的情况扔掉最后再加进来。考虑让一个 \(S\) 在最小的 \(k\) 处被统计。枚举 \(u\) 提为根,考虑哪些 \(k\) 使得不存在更小的点 \(v\)。那么 \(v\) 必然在 \(u\) 的“未溢出”子树中,也就是距离 \(u\) 最远的点所在的子树。
补充一下概念,在 \(S(u,k)\) 中,\(u\) 的“未溢出子树”是指子树内存在一点未被覆盖,“溢出子树”反之。
进一步的,只需考虑该子树的根也就是与 \(u\) 相邻的点 \(v\) 即可,判断 \(S(v,k-1)=S(u,k)\)。首先 \(v\) 子树肯定能被覆盖,考虑 \(u\) 的其它溢出子树是否能被覆盖。记 \(f_u\) 表示距离 \(u\) 最远的点的距离,\(g_u\) 表示次远点(不能和 \(f_u\) 在同一棵子树中,假如 \(u\) 只有一棵子树那么取 \(0\)),那么 \(S(v,k-1)=S(u,k)\) 当且仅当 \(g_u\le k-2\)。
注意一下,上述讨论默认了 \(S(u,k)\) 有且仅有一棵未溢出子树。其实就算存在其它未溢出子树,上述判定式仍然成立,因为 \(g_u>k>k-2\)。
对了因为不考虑整棵树所以 \(k\le f_u-1\)。综上,合法的 \(k\in [0,\min(f_u-1,g_u+1)]\)。
现在考虑有的点不可选择的情况。我们仍然让 \(S\) 在其最小点 \(u\) 被统计,即使该点不可选择。只不过要额外判定存在一个可选择点 \(v\) 满足 \(S(v,k^\prime)=S\)。
假如 \(u\) 可以选择那么没有影响,否则,考虑何时存在 \(S(v,k^\prime)=S(u,k)\)。由于 \(u\) 是最小点所以 \(v\) 只能在 \(u\) 的溢出子树中。不难发现只要 \(u\) 的溢出子树中存在一个可选择的点 \(v\),那么必然可以构造 \(k^\prime\) 使得 \(S(v,k^\prime)=S(u,k)\)。
于是我们记录 \(h_u\) 表示 \(u\) 的合法子树中最大深度最小的子树深度是多少,合法子树满足子树内存在一个可被选择的点。那么 \(k\in [h_u,\min(f_u-1, g_u+1)]\)。
\(f,g,h\) 不难换根 dp 维护,复杂度 \(O(n)\)。
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 2e5 + 5, inf = 1e8;
int n, u, v, g[N], h[N], vis[N], dis2[N], vis2[N];
vector<int> to[N];
struct node{int x, y;} f[N], dis[N];
LL ans;
char c[N];
inline void upd(node &a, int x){
if(x >= a.x) a.y = a.x, a.x = x;
else a.y = max(a.y, x);
}
inline void dfs(int u, int fa){
f[u] = {0, 0}, h[u] = c[u] == '1' ? 0 : inf;
dis[u] = {0, 0}, vis[u] = c[u] == '1';
for(auto v : to[u])
if(v ^ fa){
dfs(v, u), vis[u] += vis[v];
upd(f[u], f[v].x + 1);
upd(dis[u], dis[v].x + 1);
if(vis[v]) h[u] = min(h[u], dis[v].x + 1);
}
}
inline void dfs2(int u, int fa){
g[u] = 0;
dis2[u] = 0;
if(fa){
g[u] = g[fa] + 1;
if(f[fa].x == f[u].x + 1) g[u] = max(g[u], f[fa].y + 1);
else g[u] = max(g[u], f[fa].x + 1);
dis2[u] = dis2[fa] + 1;
if(dis[fa].x == dis[u].x + 1) dis2[u] = max(dis2[u], dis[fa].y + 1);
else dis2[u] = max(dis2[u], dis[fa].x + 1);
if(vis[1] - vis[u] > 0) h[u] = min(h[u], dis2[u]);
}
for(auto v : to[u])
if(v ^ fa) dfs2(v, u);
}
signed main(){
cin >> n;
for(int i = 1; i < n; ++i) scanf("%d%d", &u, &v), to[u].push_back(v), to[v].push_back(u);
scanf("%s", c + 1);
dfs(1, 0), dfs2(1, 0);
for(int i = 1; i <= n; ++i){
upd(f[i], g[i]);
int L = h[i], R = min(f[i].x - 1, f[i].y + 1);
ans += max(0, R - L + 1);
}
cout << ans + 1;
return 0;
}

浙公网安备 33010602011771号