Maximum White Subtree
1 min readPS
Codeforces Round 627 F
문제
난이도: 1800
풀이
정점 를 포함하는 서브트리의 의 최댓값을 라 합시다.
전체 문제를 풀기 전에 앞서 트리의 루트 에 대해 을 구해 봅시다.
이는 트리 DP로 재귀적으로 구할 수 있습니다.
정점 를 루트로 하는 서브트리만 고려했을 때 를 포함하는 서브트리의 의 최댓값을 라 합시다.
가 리프 노드인 경우 의 색에 따라서 가 정해집니다.
리프 노드가 아닌 경우 의 자식 에 대해 인 경우를 모두 서브트리에 포함시키면 가 최대가 되므로 입니다.
해당 점화식으로 을 에 구할 수 있습니다.
을 루트로 하는 서브트리는 전체 트리와 같으므로 입니다.
이제 전방향 DP를 이용해서 의 한 자식 에 대한 를 구할 수 있습니다.
먼저 가 의 정답 서브트리에 포함되는 경우를 생각해 봅시다. 그렇다면 이어야 합니다.
을 포함하는 경우는 자명하게 과 같습니다.
을 포함하지 않는 경우는 의 서브트리로만 구성하는 경우와 같고, 따라서 가 됩니다.
따라서 입니다.
가 의 정답 서브트리에 포함되지 않는 경우를 생각해 봅시다. 그렇다면 입니다.
을 포함하는 경우는 입니다.
을 포함하지 않는 경우는 위에서 본 것과 같이 가 됩니다.
따라서 입니다.
구한 를 이용해서 의 자식들의 도 계산해주면 모든 정점의 를 총 에 계산할 수 있습니다.
코드
#include <bits/stdc++.h>
using namespace std;
int color[202020];
vector<int> adj[202020];
int subdiff[202020];
int ans[202020];
void calcDiff(int cur, int parent) {
subdiff[cur] = color[cur];
for (int child : adj[cur]) {
if (child == parent) continue;
calcDiff(child, cur);
subdiff[cur] += max(0, subdiff[child]);
}
}
void calcAns(int cur, int parent) {
for (int child : adj[cur]) {
if (child == parent) continue;
if (subdiff[child] <= 0)
ans[child] = max(subdiff[child], subdiff[child] + ans[cur]);
else ans[child] = max(subdiff[child], ans[cur]);
calcAns(child, cur);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
int a;
cin >> a;
color[i] = 2 * a - 1; // 1 if white and -1 if black
}
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
calcDiff(1, 0);
ans[1] = subdiff[1];
calcAns(1, 0);
for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
return 0;
}댓글
이름과 이메일을 입력해 댓글을 남겨주세요.