codeforces 682C. Alyona and the Tree
题意
有一颗树,树上的点和边都有权值。要求删除树上若干节点,使得树上每个节点u到其子树上的节点v的 dis(u,v)≤a(u) 。问最少需要删除多少个节点。
思路
类似与最大连续子段和的思想,对于每个节点是否要保留,在于是否有从根节点方向到以他为结尾的树链的权值比其点权大,有则删除该子树,无则保留该节点。
code
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXN (100000 + 5)
#define INF (999999999)
int n;
int a[MAXN];
int c[MAXN], dp[MAXN], ans;
std::vector<pair<int, int> > v[MAXN];
void CN (int rt) {
if (v[rt].size() == 0) {
c[rt] = 1;
return;
}
c[rt] = 1;
for (int i=0; i<v[rt].size(); i++) {
CN(v[rt][i].first);
c[rt] += c[v[rt][i].first];
}
}
void DP (int rt) {
if (v[rt].size() == 0) {
return ;
}
for (int i=0; i<v[rt].size(); i++) {
pair<int, int> th = v[rt][i];
if (dp[rt] > 0) dp[th.first] = dp[rt] + th.second;
else dp[th.first] = th.second;
if (dp[th.first] <= a[th.first]) {
DP(th.first);
} else {
ans += c[th.first];
}
}
}
int main () {
ios::sync_with_stdio(false);
cin >> n;
for (int i=1; i<=n; i++) {
cin >> a[i];
}
int tmpa, tmpb;
for (int i=2; i<=n; i++) {
cin >> tmpa >> tmpb;
v[tmpa].push_back(make_pair(i, tmpb));
}
ans = 0;
CN(1);
DP(1);
cout << ans << endl;
return 0;
}