C. Garland
链接:
http://codeforces.com/contest/767/problem/C
题意:
给你一颗树,其中包含N个点,让你将这颗树剪去两条边,使得变成三部分,要求三部分的权值和相等。
题解:
1、我们设定sum【i】表示以i作为根的子树权值和。
那么过程维护,sum【i】+=sum【v】;
2、如果全部点的权值和不是3的倍数,那么显然无解,否则考虑:
①遇到了一个点u,此时sum【u】=tot/3;那么这个点就可以将其拆除出来。
②将一个点拆出来的同时,设定sum【u】=0;回溯,继续找下一个tot/3
③如果过程中遇到了两个sum【u】=tot;此时存在解。
代码:
1 #include <map> 2 #include <set> 3 #include <cmath> 4 #include <queue> 5 #include <stack> 6 #include <cstdio> 7 #include <string> 8 #include <vector> 9 #include <cstring> 10 #include <iostream> 11 #include <algorithm> 12 #include <functional> 13 using namespace std; 14 #define rep(i,a,n) for (int i=a;i<=n;i++) 15 #define per(i,a,n) for (int i=n;i>=a;i--) 16 #define pb push_back 17 #define mp make_pair 18 #define all(x) (x).begin(),(x).end() 19 #define fi first 20 #define se second 21 #define SZ(x) ((int)(x).size()) 22 typedef vector<int> VI; 23 typedef long long ll; 24 typedef pair<int, int> PII; 25 const ll mod = 1000000007; 26 // head 27 28 const int maxn = 1e6 + 7; 29 VI tree[maxn]; 30 int val[maxn]; 31 int sum[maxn]; 32 int n, tot, ans1, ans2, root; 33 34 void dfs(int u) 35 { 36 sum[u] = val[u]; 37 for (int i = 0; i<tree[u].size(); i++){ 38 int v = tree[u][i]; 39 dfs(v); 40 sum[u] += sum[v]; 41 } 42 if (sum[u] == tot){ 43 if (u == root) return; 44 if (ans1 == -1){ 45 ans1 = u; 46 sum[u] = 0; 47 } 48 else if (ans2 == -1){ 49 ans2 = u; 50 sum[u] = 0; 51 } 52 } 53 } 54 55 int main() 56 { 57 cin >> n; 58 rep(i, 1, n) { 59 int a; 60 scanf("%d%d", &a, val + i); 61 tot += val[i]; 62 if (a == 0) { 63 root = i; 64 continue; 65 } 66 tree[a].pb(i); 67 } 68 if (tot % 3) return 0 * printf("-1 "); 69 tot /= 3; 70 ans1 = ans2 = -1; 71 dfs(root); 72 if (ans1 == -1 || ans2 == -1) cout << -1 << endl; 73 else cout << ans1 << " " << ans2 << endl; 74 return 0; 75 }