题目链接:http://codeforces.com/contest/767/problem/C
题解:类似于提着一串葡萄,用剪刀剪两条藤,葡萄分成了三串。问怎样剪才能使三串葡萄的质量相等。
首先要做的就是统计葡萄的总质量tot。之后就是找到两子串质量为(tot/3)的葡萄(如果除不尽,则必定找不到),那么剩下的就是dfs搜索了。
我一开始的做法是先建一棵记录子树质量和的树,然后再从上往下dfs,如果找到了,就把它剪掉。后来发现被剪掉的那一串可能就含有两串质量为(tot/3)的葡萄(这里质量 可为负数), 所以这种方法行不通。
那么正确的做法是先深入到最底层(叶子结点),然后再从下往上搜索,这个过程与建树的过程是一致的。所以可以将两个过程合并在一起。
代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<queue> 7 #include<vector> 8 #include<map> 9 #include<string> 10 #include<set> 11 #define LL long long 12 #define MAX(a,b) (a>b?a:b) 13 #define MIN(a,b) (a<b?a:b) 14 #define INF 0x7fffffff 15 #define LNF ((1LL<<62)-1) 16 #define maxn 200010 17 18 using namespace std; 19 20 int n, tot = 0,cnt = 0, sum[1000005], vis[1000005]; 21 vector<int>child[1000005]; 22 int ans[5]; 23 24 int build(int rt) 25 { 26 vis[rt] = 1; 27 int m = child[rt].size(); 28 for(int i = 0; i<m; i++) 29 { 30 if(!vis[child[rt][i]]) 31 sum[rt] += build(child[rt][i]); 32 33 if(cnt==2) 34 return 0; 35 } 36 37 if(sum[rt]==tot) 38 { 39 ans[cnt++] = rt; 40 return 0; 41 } 42 else return sum[rt]; 43 } 44 45 int main() 46 { 47 int rt,v; 48 scanf("%d",&n); 49 for(int i = 1; i<=n; i++) 50 { 51 scanf("%d%d",&v,&sum[i]); 52 53 if(v) 54 child[i].push_back(v); 55 child[v].push_back(i); 56 57 tot += sum[i]; 58 if(!v) rt = i, vis[rt] = 1; 59 } 60 61 if(tot%3) 62 { 63 puts("-1"); 64 return 0; 65 } 66 67 tot /= 3; 68 int m = child[rt].size(); 69 for(int i = 0; i<m; i++) 70 { 71 build(child[rt][i]); 72 if(cnt==2) break; 73 } 74 75 if(cnt==2) 76 printf("%d %d\n",ans[0],ans[1]); 77 else 78 puts("-1"); 79 80 }