版权声明:希望能在自己成长的道路上帮到更多的人,欢迎各位评论交流 https://blog.csdn.net/yiqzq/article/details/82145789
原题地址:http://codeforces.com/contest/767/problem/C
题意:给出一棵树,每个节点有一个权值,现在要将节点分成3份,使得每一份权值都相同.
思路:一开始直接dfs从根节点开始搜索,然后WA在了第9组样例,看了大佬的解释才知道,由于负数的存在,使得从根节点开始是行不通的,正确的做法应该是从最低从开始判断.
大佬的说法:就是一个点加和与它其中一个子树的加和相同,但是总加和的1/3不为0(不理解的可以试一下这组数据 5 0 3 1 1 1 0 2 2 3 3,自己画一下)
#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
struct node {
int v, nxt;
} e[maxn << 1];
int tot, head[maxn];
void init_head() {
tot = 0;
CLR(head, -1);
}
void add_edge(int u, int v) {
e[tot].v = v;
e[tot].nxt = head[u];
head[u] = tot++;
}
vector<int>v;
int tmp[maxn], n, root;
int sum, half, num;
int dfs1(int u, int fa) {
for (int i = head[u]; ~i; i = e[i].nxt) {
int v = e[i].v;
if (v == fa) continue;
tmp[u] += dfs1(v, u);
}
/*
要从底层开始判,不然的话,由于负数的存在,会有错
*/
if (tmp[u] == half && u != root) {//不能是根节点
v.push_back(u);
tmp[u] = 0;
}
return tmp[u];
}
int main() {
init_head();
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int u, v;
scanf("%d%d", &u, &v);
if (u == 0) {
root = i;
} else {
add_edge(i, u);
add_edge(u, i);
}
tmp[i] = v;
sum += v;
}
if (sum % 3) {//如果总和不能整除3,那么就一定不能成功
printf("-1\n");
return 0;
}
half = sum / 3;
dfs1(root, -1);
if (v.size() < 2) printf("-1\n");//如果成功的节点少于2个,那么就是-1
else printf("%d %d\n", v[0], v[1]);
return 0;
}