CF 767C Garland

题目链接:传送门
题面:
n n n个节点的树
i i i个节点权值为 a i a_i ai
n &lt; = 1 0 6 n&lt;=10^6 n<=106
− 100 &lt; = a i &lt; = 100 -100&lt;=a_i&lt;=100 100<=ai<=100
问是否能够删除掉两条边,使得该树分成三个不为空,并且每部分权值之和相等.
无解输出 − 1 -1 1否则输出要删除边( u − &gt; v u-&gt;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");
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

良月澪二

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值