CF1654G Snowy Mountain 题解
Un1quAIoid · · 题解
洛谷传送门:Snowy Mountain
贡献一个
初始可以用 BFS 求出每个点的高度
接下来我们来考虑如何使得操作数最大化,这点其它题解讲的很明白,从点
考虑使用点分治计算每个点
使用同样的方法,我们也可以用第二遍 DFS 处理出从连通块内每个点
这样复杂度是
这意味着变量
代码:
//CF1654G Snowy Mountain
//O(nlogn)解法
#include <bits/stdc++.h>
#define lowbit(x) (x & -x)
#define eb emplace_back
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long ll;
const int N = 2e5+5;
const int Mod = 998244353;
int n, h[N], ans[N];
int siz[N];
bool b[N], vis[N];
vector<int> T[N];
queue<int> Q;
void dfs_centre(int x, int fa, int sizz, int &c) {
siz[x] = 1;
int mx = 0;
for (auto son : T[x]) {
if (son == fa || vis[son]) continue;
dfs_centre(son, x, sizz, c);
siz[x] += siz[son];
mx = max(mx, siz[son]);
}
if (mx <= sizz / 2 && siz[x] >= sizz / 2) c = x;
}
int L, R, mn[N * 2];
void dfs(int x, int fa, int mx, int sum, bool t) {
mx = max(mx, t ? sum : -sum);
if (t) {
if (sum >= mx && sum + n >= L)
ans[x] = min(ans[x], mn[min(R, sum + n)]);
} else if (b[x]) {
while (R < mx + n) mn[++R] = n;
while (L > mx + n) mn[--L] = n;
mn[mx + n] = min(mn[mx + n], h[x]);
}
for (auto son : T[x]) {
if (son == fa || vis[son]) continue;
if (h[son] == h[x]) dfs(son, x, mx, sum - 1, t);
else if (t ^ (h[x] > h[son])) dfs(son, x, mx, sum + 1, t);
}
}
inline void calc(int x) {
L = R = mn[n] = n;
dfs(x, x, 0, 0, 0);
for (int i = L + 1; i <= R; i++) mn[i] = min(mn[i], mn[i - 1]);
dfs(x, x, 0, 0, 1);
}
void solve(int x, int sizz) {
dfs_centre(x, x, sizz, x);
vis[x] = 1;
calc(x);
for (auto son : T[x]) {
if (vis[son]) continue;
solve(son, siz[son] > siz[x] ? sizz - siz[x] : siz[son]);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
h[i] = -1;
if (b[i]) {
h[i] = 0;
Q.push(i);
}
}
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
T[u].pb(v), T[v].pb(u);
}
while (!Q.empty()) {
int top = Q.front();
Q.pop();
for (auto v : T[top]) if (!~h[v]) {
h[v] = h[top] + 1;
Q.push(v);
}
}
for (int i = 1; i <= n; i++) {
ans[i] = h[i];
b[i] = 0;
for (auto j : T[i]) if (h[i] == h[j])
{ b[i] = 1; break; }
}
solve(1, n);
for (int i = 1; i <= n; i++) printf("%d ", 2 * h[i] - ans[i]);
return 0;
}