传送门
貌似是个可并堆的模板题,笔者懒得写左偏堆了,直接随机堆水过。实际上这题就是维护一个可合并的大根堆一直从叶子合并到根,如果堆中所有数的和超过了上限就一直弹直到所有数的和不超过上限为止,最后对于当前的子树,这样剩下的堆中的元素个数一定是最多的,然后直接统计答案就行了。
代码:
#include<bits/stdc++.h>
#define N 100005
#define ll long long
using namespace std;
inline ll read(){
ll ans=0,w=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans*w;
}
inline void write(int x){
if(x<0)x=-x,putchar('-');
if(x>9)write(x/10);
putchar((x%10)^48);
}
int son[N][2],n,first[N],cnt=0,rt[N];
ll m,w[N],l[N],siz[N],tsiz[N],sum[N],ans=0;
struct Node{int v,next;}e[N<<1];
inline void add(int u,int v){e[++cnt].v=v,e[cnt].next=first[u],first[u]=cnt;}
inline int merge(int a,int b){
if(!a||!b)return a+b;
if(w[a]<w[b])swap(a,b);
son[a][0]=merge(son[a][0],b);
if(rand()%2)swap(son[a][0],son[a][1]);
return a;
}
inline void dfs(int p){
rt[p]=p,siz[p]=1,tsiz[p]=1,sum[p]=w[p];
for(int i=first[p];i;i=e[i].next){
int v=e[i].v;
dfs(v),siz[p]+=siz[v],tsiz[p]+=tsiz[v],sum[p]+=sum[v],rt[p]=merge(rt[p],rt[v]);
}
while(sum[p]>m)sum[p]-=w[rt[p]],--tsiz[p],rt[p]=merge(son[rt[p]][0],son[rt[p]][1]);
ans=max(ans,l[p]*tsiz[p]);
}
int main(){
srand(time(NULL));
n=read(),m=read();
for(int i=1;i<=n;++i)add(read(),i),w[i]=read(),l[i]=read(),son[i][0]=son[i][1]=0;
dfs(1);
printf("%lld",ans);
return 0;
}