题目 t−h≤k 的限制其实就是选一条到叶节点的链,然后再选k个的最大值(因为vi都大于零)。
因为 ai>1 的点,肯定是先选了第一个才会选第二个
所以可以把 ai>1 的点拆成两个点 i′,i′′ , ai′=1 , ai′′=ai−1 ,让 i′′ 变成 i′ 的儿子。
这个树上依赖背包可以通过两个遍历子树顺序相反的后序遍历和队列优化 O(NK) 求出每个点选 K 个的最大价值。
然后枚举每个叶子(拆点前的叶子),用两个后序遍历中的DP值更新答案就可以了。
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=40010,K=500010;
bool bg;
int t,n,k,cnt,ncnt,DEPT,iG[N],a[N],v[N],lef[N],dpt[N],sz[N],son[N];
int f[51000010],g[51000010];
int val[N];
ll tot;
struct edge{
int t,nx;
}E[N];
int Ap[N],Bp[N],pa[N],pb[N],A[N],B[N],At,Bt;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void rea(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
inline void adde(int x,int y){
E[++cnt].t=y; E[cnt].nx=iG[x]; iG[x]=cnt;
}
void dfsf(int x){
Ap[x]=At; sz[x]=1;
for(int i=iG[x];i;i=E[i].nx){
val[E[i].t]=val[x]+v[E[i].t];
dpt[E[i].t]=dpt[x]+1;
dfsf(E[i].t),sz[x]+=sz[E[i].t];
}
A[++At]=x; pa[x]=At;
}
void dfsb(int x){
vector<int> son; Bp[x]=Bt;
for(int i=iG[x];i;i=E[i].nx) son.push_back(E[i].t);
for(int i=son.size()-1;~i;i--) dfsb(son[i]);
B[++Bt]=x; pb[x]=Bt;
}
#define F(x,y) f[(x)*(k+1)+(y)]
#define G(x,y) g[(x)*(k+1)+(y)]
//ll &F(int x,int y){ return f[(x)*(k+1)+(y)]; }
//ll &G(int x,int y){ return g[(x)*(k+1)+(y)]; }
int Q[K],Q1[K],qh,qt;
bool ed;
inline void DP(int *A,int *p,int *f){
for(int i=1;i<=ncnt;i++){
int x=A[i];
int *ff=f+(i-1)*(k+1),*fc=f+i*(k+1);
memcpy(fc,f+p[x]*(k+1),sizeof(int)*(k+1));
//for(int j=0;j<=k;j++) fc[j]=F(p[x],j);
if(a[x]==0) continue;
if(a[x]==1){
for(int j=1;j<=k;j++)
fc[j]=max(fc[j],ff[j-1]+v[x]);
continue;
}
qh=qt=1;
Q[qh]=0; Q1[qh]=0;
for(int j=1;j<=k;j++){
fc[j]=max(fc[j],j*v[x]+Q1[qh]);
while(qh<=qt && Q[qh]<=j-a[x]) qh++;
int cur=ff[j]-j*v[x];
while(qh<=qt && Q1[qt]int ans;
int main(){
rea(t);
while(t--){
rea(n); rea(k);
for(int i=1;i<=n;i++) iG[i]=lef[i]=val[i]=son[i]=0;
//memset(f,0,sizeof(f));
//memset(g,0,sizeof(g));
cnt=0; ncnt=n; At=Bt=0; ans=0; tot=0;
for(int i=1;i<=n;i++){
int p; rea(p); rea(a[i]); rea(v[i]); tot+=a[i];
if(p) adde(p,i),lef[p]=1;
if(a[i]>1)
a[son[i]=++ncnt]=a[i]-1,v[ncnt]=v[i],a[i]=1,adde(i,ncnt),lef[ncnt]=1;
}
val[1]=v[1]; dpt[1]=1;
dfsf(1); dfsb(1);
DP(A,Ap,f);
DP(B,Bp,g);
//printf("%d\n",clock()-ttt);
/*for(int i=1;i<=n;i++)
for(int j=0;j<=k;j++)
cout<
for(int i=1;i<=n;i++)
if(!lef[i]){
int cur=min((ll)k,tot-dpt[i]);
int *ff=f+(pa[i]-1)*(k+1),*gg=g+(pb[i]-sz[i])*(k+1);
for(int j=0;j<=cur;j++)
ans=max(ans,ff[j]+gg[cur-j]+val[i]);
}
//printf("%d\n",clock()-ttt);
printf("%d\n",ans);
}
//printf("%d\n",(&ed-&bg)/1024/1024);
return 0;
}