스크류바가 코딩하는 블로그
카테고리아카이브태그소개
자동

© 2026 스쿠루. All rights reserved.

개인정보 처리방침RSS

Maximum White Subtree

2026.08.07|1 min read|PS

Codeforces Round 627 F

Codeforces그래프 이론그래프 탐색트리DP트리 DP전방향 트리 DP

문제

링크: Maximum White Subtree

난이도: 1800

풀이

정점 vvv를 포함하는 서브트리의 cntw−cntbcnt_w - cnt_bcntw​−cntb​의 최댓값을 ansvans_vansv​라 합시다.

전체 문제를 풀기 전에 앞서 트리의 루트 rrr에 대해 ansrans_ransr​을 구해 봅시다.

이는 트리 DP로 재귀적으로 구할 수 있습니다.

정점 vvv를 루트로 하는 서브트리만 고려했을 때 vvv를 포함하는 서브트리의 cntw−cntbcnt_w - cnt_bcntw​−cntb​의 최댓값을 dpvdp_vdpv​라 합시다.

vvv가 리프 노드인 경우 vvv의 색에 따라서 dpvdp_vdpv​가 정해집니다.

리프 노드가 아닌 경우 vvv의 자식 ccc에 대해 dpc>0dp_c > 0dpc​>0인 경우를 모두 서브트리에 포함시키면 cntw−cntbcnt_w - cnt_bcntw​−cntb​가 최대가 되므로 dpv=∑max⁡(0,dpc)dp_v = \sum \max(0, dp_c)dpv​=∑max(0,dpc​)입니다.

해당 점화식으로 dprdp_rdpr​을 O(n)O(n)O(n)에 구할 수 있습니다.

rrr을 루트로 하는 서브트리는 전체 트리와 같으므로 ansr=dprans_r = dp_ransr​=dpr​입니다.

이제 전방향 DP를 이용해서 rrr의 한 자식 ccc에 대한 ansansans를 구할 수 있습니다.

먼저 ccc가 rrr의 정답 서브트리에 포함되는 경우를 생각해 봅시다. 그렇다면 dpc>0dp_c > 0dpc​>0이어야 합니다.

rrr을 포함하는 경우는 자명하게 ansrans_ransr​과 같습니다.

rrr을 포함하지 않는 경우는 ccc의 서브트리로만 구성하는 경우와 같고, 따라서 dpcdp_cdpc​가 됩니다.

따라서 ansc=max⁡(dpc,ansr)ans_c = \max(dp_c, ans_r)ansc​=max(dpc​,ansr​) 입니다.

ccc가 rrr의 정답 서브트리에 포함되지 않는 경우를 생각해 봅시다. 그렇다면 dpc≤0dp_c \leq 0dpc​≤0입니다.

rrr을 포함하는 경우는 dpc+ansrdp_c + ans_rdpc​+ansr​ 입니다.

rrr을 포함하지 않는 경우는 위에서 본 것과 같이 dpcdp_cdpc​가 됩니다.

따라서 ansc=max⁡(dpc,dpc+ansr)ans_c = \max(dp_c, dp_c + ans_r)ansc​=max(dpc​,dpc​+ansr​) 입니다.

구한 anscans_cansc​를 이용해서 ccc의 자식들의 ansansans도 계산해주면 모든 정점의 ansansans를 총 O(n)O(n)O(n)에 계산할 수 있습니다.

코드

#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;
}

목차

  • 문제
  • 풀이
  • 코드

댓글

이름과 이메일을 입력해 댓글을 남겨주세요.