题目链接:传送门
题面:
n
n
n个节点的树
第
i
i
i个节点权值为
a
i
a_i
ai
n
<
=
1
0
6
n<=10^6
n<=106
−
100
<
=
a
i
<
=
100
-100<=a_i<=100
−100<=ai<=100
问是否能够删除掉两条边,使得该树分成三个不为空,并且每部分权值之和相等.
无解输出
−
1
-1
−1否则输出要删除边(
u
−
>
v
u->v
u−>v)的
v
v
v节点序号
STL吼啊
详细解释在代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <complex>
#include <algorithm>
#include <climits>
#include <queue>
#include <map>
#include <vector>
#include <iomanip>
#define A 1000010
#define B 2010
#define ll long long
using namespace std;
int n, a, b, root, cnt, sum, rem;
int pre[A], size[A], w[A], ans[3], cans;
vector<int> v[A]; //vector存图
void dfs(int fr) {
size[fr] = w[fr]; //子树权值一开始是这个点的权值
for (int i = 0; i < v[fr].size(); i++) //遍历相邻的每个点
if (v[fr][i] != pre[fr]) { //不是同一个结点
dfs(v[fr][i]); //继续往下搜
size[fr] += size[v[fr][i]]; //算上子树大小
}
if (size[fr] == (sum / 3) and pre[fr])
ans[++cans] = fr, size[fr] = 0; //算进答案中了就去掉这颗子树
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
cnt++;
scanf("%d%d", &a, &b);
if (!a) {
root = cnt; //记录下根节点
w[cnt] = b; //点的权值
pre[cnt] = a; //记录下前驱
sum += b; //这颗树的点权和
}
else {
w[cnt] = b;
pre[cnt] = a;
v[cnt].push_back(a); //双向存图
v[a].push_back(cnt);
sum += b;
}
}
if (sum % 3) return puts("-1") & 0; //怎么也分不成三份
dfs(root);
if (cans >= 2) printf("%d %d\n", ans[1], ans[2]);
else puts("-1");
}