#左偏树,树形dp#洛谷 1552 [APIO2012]派遣
分析
那我指定管理层之后,选择薪水越小的人越好,
考虑小根堆,由于需要合并,所以采用左偏树
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=100011; typedef long long lll;
struct node{int y,next;}e[N];
int n,siz[N],lead[N],as[N],et; lll ans,m,c[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
struct Leftist_Tree{
int rt[N],son[N][2],w[N],d[N];
inline signed Merge(int fi,int se){
if (!fi||!se) return fi|se;
if (w[fi]<w[se]) swap(fi,se);
son[fi][1]=Merge(son[fi][1],se);
if (d[son[fi][0]]<d[son[fi][1]]) swap(son[fi][0],son[fi][1]);
d[fi]=d[son[fi][1]]+1;
return fi;
}
inline signed Pop(int now){
rr int t1=son[now][0],t2=son[now][1];
rt[t1]=t1,rt[t2]=t2,w[now]=-1,
son[now][0]=son[now][1]=d[now]=0;
return Merge(t1,t2);
}
}Tre;
inline void dfs(int x){
for (rr int i=as[x];i;i=e[i].next){
dfs(e[i].y);
Tre.rt[x]=Tre.Merge(Tre.rt[x],Tre.rt[e[i].y]);
c[x]+=c[e[i].y],siz[x]+=siz[e[i].y];
}
while (c[x]>m){
c[x]-=Tre.w[Tre.rt[x]],--siz[x],
Tre.rt[x]=Tre.Pop(Tre.rt[x]);
}
ans=max(ans,1ll*lead[x]*siz[x]);
}
signed main(){
n=iut(),m=iut(),Tre.d[0]=-1;
for (rr int i=1;i<=n;++i){
rr int F=iut(); if (F) e[++et]=(node){i,as[F]},as[F]=et;
c[i]=Tre.w[i]=iut(),Tre.rt[i]=i,lead[i]=iut(),siz[i]=1;
}
dfs(1);
return !printf("%lld",ans);
}