【问题描述】
在一个原始森林里,有人发现了一颗根编号为1的神奇树,它的每个顶点以及每条边上都标有一个数字。
然而,他发现这颗树上有些顶点有瑕疵,也称为瑕疵点。一个顶点 v 被称为瑕疵点是指在它的子树中存在点 u,使得dist(v, u)>au,这里au是标注在顶点 u 上的数字,而dist(v, u)是所有标注在从顶点 v 到顶点 u 的路径上边的数字之和。
如果一个顶点只有一条路径相连,则这个顶点是树的叶子节点。但是树的根节点是叶子节点,当且仅当数树仅有一个单一顶点,即根节点。
这人决定删除一些叶子节点,直到整颗树不存在任何瑕疵点。那么,需要删除的叶子节点的最少数是多少?
【输入形式】
输入的第一行为一个整数 n (1≤ n ≤ 105 )。
接下来一行为 n 个整数a1、a2、...、an(1≤ ai ≤109),这里 ai 是标注在顶点 i 上的数字。
接下来的 n - 1描述了树中边的情况,第 i 行有两个整数 pi和ci (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
【提示】
以下是可能的处理过程
【来源】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;
}