实训五#5.10树的优化

【问题描述】

        在一个原始森林里,有人发现了一颗根编号为1的神奇树,它的每个顶点以及每条边上都标有一个数字。

   然而,他发现这颗树上有些顶点有瑕疵,也称为瑕疵点。一个顶点 v 被称为瑕疵点是指在它的子树中存在点 u,使得dist(vu)>au,这里au是标注在顶点 u 上的数字,而dist(vu)是所有标注在从顶点 v 到顶点 u 的路径上边的数字之和。

   如果一个顶点只有一条路径相连,则这个顶点是树的叶子节点。但是树的根节点是叶子节点,当且仅当数树仅有一个单一顶点,即根节点。

   这人决定删除一些叶子节点,直到整颗树不存在任何瑕疵点。那么,需要删除的叶子节点的最少数是多少?

【输入形式】

     输入的第一行为一个整数 n (1≤ n ≤ 105 )。

     接下来一行为 n 个整数a1a2、...、an(1≤ ai ≤109),这里 a是标注在顶点 i 上的数字。

  接下来的 n - 1描述了树中边的情况,第 i 行有两个整数 pici (1 ≤ pi ≤ n,  - 109 ≤ ci ≤ 109),这意味着在顶点 i +1 和 pi之间有边相连,其上标有数字ci
【输出形式】

    输出一个整数,表示需要删除的最少叶子节点数。

【样例输入】

9
88 22 83 14 95 91 98 53 11
3 24
7 -8
1 67
1 64
9 65
5 12
6 -80
3 8

【样例输出】

5

【提示】
以下是可能的处理过程

QQ图片20210604150127.png

【来源】codeforces 682C

#include <bits/stdc++.h>
using namespace std;
#define MAXSIZE 100001
int n; 
int p[MAXSIZE], c[MAXSIZE], a[MAXSIZE];

int dist(int root, int u) {
    int length=0;
    while (u!=root) {
        length+=c[u];
        u=p[u];
    }
    return length;
}

bool DeleteOrNot(int u) {
    int root=p[u];
    while (root!=0) {
        if (dist(root, u)>a[u]) return 1;
        root=p[root];
    }
    return 0;
}

int ChildNum(int root) {
    int c=0;
    if (root==1) return n;
    for (int i=1; i<=n; i++) {
        int j=i;
        while (j!=root&&j!=1) 
            j=p[j]; 
        if (j==root) c++;
    }
    return c;
}

int DeleteNum(int root) {
    if (DeleteOrNot(root)) return ChildNum(root);
    vector<int> childs;
    for (int i=1; i<=n; i++)
        if (p[i]==root) childs.push_back(i);
    int size=(int)childs.size(), c=0;
    for (int i=0; i<size; i++) c+=DeleteNum(childs[i]);
    return c;
}

int main() {
    cin>>n;
    for (int i=1; i<=n; i++) cin>>a[i];
    for (int i=2; i<=n; i++) cin>>p[i]>>c[i];
    cout<<DeleteNum(1);
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值