2019 KCPC pretty

2019 KCPC 얼마나 예뻐? (신입생 부문 H번 / 일반 부문 D번) 코드 제출 url

올바른 괄호 문자열을 조금 바꾸어 말하자면, ‘(‘을 +1로, ‘)’을 -1로 대응하였을 때 prefix sum의 최솟값이 0이고 total sum이 0인 문자열을 의미합니다.

( prefix sum이란 $ prefix_{sum}[i]=\sum_{0}^{i}arr[j] $ 으로, 0번부터 i번까지의 합을 의미합니다.)

따라서 우리는 어떤 sub tree가 pretty 한지 알기 위해서 자식 노드들의 (total_sum, min(prefix_sum) 만 알면 됩니다.

어떤 sub tree를 1(루트) $ \rightarrow $ 2 $ \rightarrow $ 3 $ \rightarrow $ 4 … 이런 식으로 진행된다면, x번째 자식 sub tree로 새로 생기는 최소값은 [1 … x-1] sum + min(x를 루트로 하는 subtree) 이므로 합을 구하는 과정에서 쉽게 같이 구할 수 있습니다.

#include <bits/stdc++.h>
#define ff first
#define ss second
#define pb push_back
using namespace std;
typedef pair<int,int> pii;
const int SZ=200005;
vector<int> graph[SZ];
int bra[SZ];
int tot;
pii tra(int p, int x){
    int sm=bra[x];
    int mn=bra[x];
    for(int nxt:graph[x]){
        if(nxt==p) continue;
        pii xx=tra(x,nxt);
        mn=min(mn,sm+xx.ss);
        sm+=xx.ff;
    }
    if(mn==0 && sm==0) tot++;
    return {sm,mn};
}
int main(void){
    ios_base::sync_with_stdio(false); cin.tie(NULL);
    int n; cin>>n;
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        bra[i]=(x==0?1:-1);
    }
    for(int i=1;i<n;i++){
        int x,y; cin>>x>>y;
        graph[x].pb(y);
        graph[y].pb(x);
    }
    for(int i=1;i<=n;i++) sort(graph[i].begin(),graph[i].end());
    tra(0,1);
    cout<<tot;
    return 0;
}