题意
一棵树上每个结点的初始值均为 0 0 0 ,需要进过若干次操作后使每个结点都落在规定的范围内。每次操作可以选择一个结点及一个非下降正整数序列,并让根节点 1 1 1 到该结点之间的 所有结点 依次加上对应的数字。问需要的最少操作次数。
正向思维可以考虑对于任一结点,其最小值是否超过了所有儿子的最大值,否则就可以选择一子结点延续操作。鉴于正向建树和遍历实在是太麻烦了, 还可以由反向将所有结点的最大值向父亲推,若父亲得到的值仍然小于父亲结点要求的最小值,则说明还需要在父亲及之前增加操作次数。
由于本题建树数据的特殊性,即:序号更大的结点一定不能是序号更小结点的祖先,可以直接偷懒进行序号倒序遍历。
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int N=2e5+10;
int fa[N],l[N],r[N],v[N];
vector<int> g[N];
void solve() {
int n;
cin>>n;
memset(v,0,sizeof(v));
// for(int i=1;i<=n;i++)
// g[i].clear();
for(int i=2;i<=n;i++){
cin>>fa[i];
// g[fa[i]].push_back(i);
}
for(int i=1;i<=n;i++)
cin>>l[i]>>r[i];
int ans=0;
for(int i=n;i>=1;i--){
v[i]=min(v[i],r[i]);
if(v[i]<l[i]){
v[i]=r[i];
ans++;
}
v[fa[i]]+=v[i];
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
while(t--)
solve();
return 0 ;
}