首先考虑
t−hmax≤k
的限制。可以看做除去最长到根链上的点各一个,剩下的最多取
k
。
可以想到枚举叶子,求必选这个叶到根路径上各一个之后,其他取
普通的树上依赖背包一般是:
按后序遍历顺序
DP
,
fi,j
表示后序遍历前
i
个中选了
考虑这道题,肯定要先
DP
预处理。但由于强制已经选了一条链,可能就会发生一些问题。
关键要进行一个拆点,考虑所有的
i
,新建点
这样就把枚举取的链和
DP
的东西分开了。即两次DP,其后序遍历儿子顺序相反,然后最后求答案时就是左半边加右半边就行了。
DP
要单调队列优化。
小错误…调了半天…
#include<cstdio>
#include<cctype>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
inline char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
char ch=gc(); int res=0;
while(!isdigit(ch)) ch=gc();
while(isdigit(ch)) res=(res<<3)+(res<<1)+ch-'0', ch=gc();
return res;
}
const int maxn=40005,maxm=500005,maxe=40005,maxnk=52000005;
int n,_n,m,Q,sz[maxn],a[maxn],v[maxn],dep[maxn],ans,f[maxnk],h[maxnk];
int fir[maxn],nxt[maxe],son[maxe],tot;
bool isleaf[maxn];
void add(int x,int y){
son[++tot]=y; nxt[tot]=fir[x]; fir[x]=tot; //printf("%d -- %d\n",x,y);
}
int vup[maxn],Tim,df1[maxn],out1[maxn],pos1[maxn],df2[maxn],out2[maxn],pos2[maxn];
void dfs1(int x){
out1[x]=Tim; sz[x]=1;
for(int j=fir[x];j;j=nxt[j])
vup[son[j]]=vup[x]+v[son[j]], dep[son[j]]=dep[x]+1, dfs1(son[j]), sz[x]+=sz[son[j]];
df1[++Tim]=x; pos1[x]=Tim;
}
int c[maxn];
void dfs2(int x){
out2[x]=Tim;
stack<int> tmp; for(int j=fir[x];j;j=nxt[j]) tmp.push(son[j]);
while(!tmp.empty()) dfs2(tmp.top()), tmp.pop();
df2[++Tim]=x; pos2[x]=Tim;
}
#define f(i,j) f[(i)*(m+1)+(j)]
#define h(i,j) h[(i)*(m+1)+(j)]
int que[maxm],que1[maxm],hd,tl;
void Dp(int f[],int df[],int out[]){
for(int i=1;i<=n;i++){
int x=df[i];
for(int j=0;j<=m;j++) f(i,j)=f(out[x],j);
if(a[x]==1){
for(int j=1;j<=m;j++) f(i,j)=max(f(i,j),f(i-1,j-1)+v[x]);
continue;
}
hd=tl=1; que[hd]=que1[hd]=0;
for(int j=1;j<=m;j++){
f(i,j)=max(f(i,j),j*v[x]+que1[hd]);
while(hd<=tl&&que[hd]<=j-a[x]) hd++;
int cur=f(i-1,j)-j*v[x];
while(hd<=tl && que1[tl]<cur) tl--;
que[++tl]=j; que1[tl]=cur;
}
}
}
LL sum_a;
void AllClear(){
memset(fir,0,sizeof(fir)); tot=0;
memset(isleaf,1,sizeof(isleaf));
//memset(f,0,sizeof(f)); memset(h,0,sizeof(h));
ans=0; sum_a=0;
}
int main(){
freopen("loj2268.in","r",stdin);
freopen("loj2268.out","w",stdout);
Q=getint();
while(Q--){
AllClear();
_n=n=getint(); m=getint();
for(int i=1;i<=_n;i++){
int x=getint(); a[i]=getint(); v[i]=getint(); isleaf[x]=false; sum_a+=a[i];
if(x) add(x,i);
if(a[i]>1) a[++n]=a[i]-1, a[i]=1, v[n]=v[i], add(i,n);
}
Tim=0; dep[1]=1; vup[1]=v[1]; dfs1(1); Tim=0; dfs2(1);
Dp(f,df1,out1);
Dp(h,df2,out2);
for(int i=1;i<=_n;i++) if(isleaf[i]){
int cnt=min((LL)m,sum_a-dep[i]);
for(int j=0;j<=cnt;j++) ans=max(ans,f(pos1[i]-1,j)+h(pos2[i]-sz[i],cnt-j)+vup[i]);
}
printf("%d\n",ans);
}
return 0;
}