左偏树。
每个子节点维护大根堆,遍历一个儿子就往自己合并,合并发现钱不够了就删除队顶。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<cmath>
const int N=100007;
typedef long long LL;
using namespace std;
int n,root,rt[N],ch[N][2],sz[N],f[N];
LL m,v[N],cs[N],w[N],ans;
template<typename T> void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar();
if(ch==‘-‘) f=-1,ch=getchar();
for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=x*10+ch-‘0‘; x*=f;
}
int ecnt,fir[N],nxt[N],to[N],dis[N];
void add(int u,int v) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
}
#define lc ch[x][0]
#define rc ch[x][1]
void update(int x) { sz[x]=sz[lc]+sz[rc]+1; v[x]=v[lc]+v[rc]+cs[x];}
int merge(int x,int y) {
if(!(x*y)) return x^y;
if(cs[x]<cs[y]) swap(x,y);
rc=merge(rc,y);
if(dis[lc]<dis[rc]) swap(lc,rc);
if(!rc) dis[x]=0;
else dis[x]=dis[rc]+1;
update(x);
return x;
}
void dfs(int x) {
for(int i=fir[x];i;i=nxt[i]) {
dfs(to[i]);
rt[x]=merge(rt[x],rt[to[i]]);
while(v[rt[x]]>m)
rt[x]=merge(ch[rt[x]][0],ch[rt[x]][1]);
}
ans=max(ans,w[x]*sz[rt[x]]);
}
int main() {
#ifdef DEBUG
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
read(n); read(m);
for(int i=1;i<=n;i++) {
read(f[i]);
read(cs[i]);
read(w[i]);
if(!f[i]) root=i;
else add(f[i],i);
rt[i]=i;
v[i]=cs[i];
sz[i]=1;
}
dfs(root);
printf("%lld\n",ans);
return 0;
}