做这题的时候现学了一波左偏树2333(好吧其实是当初打完板子就给忘了)
不难发现肯定是选子树里权值最小的点且选得越多越好
但如果在每一个点维护一个小根堆,我们得一直找知道权值大于m为止,时间会炸
于是我们对每一个点维护一个大根堆,一直pop直到堆里总的权值小于m为止,此时堆里的元素个数就是总共的人数
不难发现每一个人最多只会被pop一次,于是时间复杂度就是$O(n logn)$
左偏树合并写错了竟然还能有67分……
1 //minamoto 2 #include<bits/stdc++.h> 3 #define ll long long 4 using namespace std; 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 6 char buf[1<<21],*p1=buf,*p2=buf; 7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 8 inline int read(){ 9 #define num ch-'0' 10 char ch;bool flag=0;int res; 11 while(!isdigit(ch=getc())) 12 (ch=='-')&&(flag=true); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return res; 17 } 18 const int N=1e5+5; 19 int head[N],Next[N],ver[N],tot; 20 inline void add(int u,int v){ 21 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 22 } 23 int val[N],rt[N],L[N],R[N],a[N],d[N],sz[N],n,m;ll sum[N],ans; 24 int merge(int x,int y){ 25 if(!x||!y) return x+y; 26 if(val[x]<val[y]) swap(x,y); 27 R[x]=merge(R[x],y); 28 if(d[R[x]]>d[L[x]]) swap(L[x],R[x]); 29 d[x]=d[R[x]]+1;return x; 30 } 31 void dfs(int u){ 32 sz[u]=1,sum[u]=val[u],rt[u]=u; 33 for(int i=head[u];i;i=Next[i]){ 34 int v=ver[i];dfs(v); 35 sz[u]+=sz[v],sum[u]+=sum[v],rt[u]=merge(rt[u],rt[v]); 36 } 37 while(sum[u]>m&&sz[u]){ 38 sum[u]-=val[rt[u]],--sz[u],rt[u]=merge(L[rt[u]],R[rt[u]]); 39 } 40 cmax(ans,1ll*sz[u]*a[u]); 41 } 42 int main(){ 43 // freopen("testdata.in","r",stdin); 44 n=read(),m=read(); 45 for(int i=1;i<=n;++i){ 46 int fa=read();val[i]=read(),a[i]=read(); 47 add(fa,i); 48 } 49 dfs(1); 50 printf("%lld ",ans); 51 return 0; 52 }