题解 P6847 【[CEOI2019] Magic Tree】
首先有一个显然的暴力dp
设
显然有
有
不难发现
于是,我们可以用一个 map 存储这些拐点,以及对应的
对于一个节点
接下来考虑
每次暴力合并 map 显然会超时,于是用启发式合并
时间复杂度
code:
#include<bits/stdc++.h>
#define MAXN 100010
#define int long long
#define iter map<int,int>::iterator
using namespace std;
int n,m,K;
int rt[MAXN],fa[MAXN],d[MAXN],w[MAXN];
map<int,int>f[MAXN];
void merge(int &a,int b){
if(f[a].size()<f[b].size())swap(a,b);
for(iter it=f[b].begin();it!=f[b].end();it++)
f[a][it->first]+=it->second;
}
signed main(){
scanf("%lld%lld%lld",&n,&m,&K);
for(int i=2;i<=n;i++)scanf("%lld",&fa[i]);
for(int i=1;i<=m;i++){
int p;scanf("%lld",&p);
scanf("%lld%lld",&d[p],&w[p]);
}
for(int i=1;i<=n;i++)rt[i]=i;
for(int i=n;i;i--){
f[rt[i]][d[i]]+=w[i];iter it;
for(it=f[rt[i]].find(d[i]),it++;it!=f[rt[i]].end();){
if(it->second>w[i]){it->second-=w[i];break;}
w[i]-=it->second;iter tmp=it;it++;f[rt[i]].erase(tmp);
}
merge(rt[fa[i]],rt[i]);
}int ans=0;
for(iter it=f[rt[1]].begin();it!=f[rt[1]].end();it++)
ans+=it->second;
printf("%lld",ans);
return 0;
}