链接
传送门
分析
这里有个非常重要的条件,pi<i,也就是说,每个节点的父节点的序号一定比自己小,排在最后的最大的i一定是叶子。这里非常有趣,想是一片片的地摘叶子。首先对于一个叶子而言,它需要一次操作次数,由于修改的变化量必须从叶子到1是递减的,如果说这片叶子的数目不足L,就直接加到R,然后更新父节点的值,这片叶子就操作完了,可以摘掉了,如果下次检查到这片叶子,发现大于R了,必须要减少量,可以减少到零,因为所有前面,已经被处理掉的叶子,给予变化量的叶子都可以减少该在当前新的叶子上的分量,但是减少到零不是最佳的,因为这样给下一片露出的新的叶子可操作的空间就便是了,要尽可能地大一些。依次类推,在整棵树上到处摘叶子,只有严格小于新的叶子的左边界的时候才需要操作次数加一,尽可能减少增量的衰退,重复利用每一片叶子的贡献。
联想
这题后面的贪心的思想和这题有点类似。
传送门
实现
#include <bits/stdc++.h>
#define ll long long
#define ls (u << 1)
#define rs (u << 1 | 1)
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 2e5 + 5;
int p[N], l[N], r[N];
ll a[N];
void solve() {
int n;
cin >> n;
for (int i = 2; i <= n; i++) cin >> p[i];
for (int i = 1; i <= n; i++) cin >> l[i] >> r[i], a[i] = 0;
int ans = 0;
for (int i = n; i >= 1; i--) {
if (a[i] < l[i]) a[i] = r[i], ans++;
if (a[i] > r[i]) a[i] = r[i];
a[p[i]] += a[i];
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}