[APIO2012]派遣 [可並堆]
阿新 • • 發佈:2018-12-02
首先想到列舉每個點作為領導 , 然後我們需要快速查出x為根的子樹可以有多少個節點
滿足這些節點加起來不超過m
於是我們從下到上合併 , 維護一個小根堆(大的在上) , 如果堆的和>m就彈出堆頂
#include<bits/stdc++.h> #define N 100050 #define LL long long using namespace std; int siz[N],sum[N],l[N],r[N],val[N]; int n,m,b[N],c[N],w[N],rt[N]; LL ans; int first[N],next[N],to[N],tot; void add(int x,int y){ next[++tot]=first[x],first[x]=tot,to[tot]=y; } int Merge(int x,int y){ if(!x||!y) return x+y; if(val[x]<val[y]) swap(x,y); l[x]=Merge(l[x],y); if(rand()%2) swap(l[x],r[x]); return x; } void Pop(int x){ int now = rt[x]; rt[x] = Merge(l[now],r[now]); siz[x]-- , sum[x]-=val[now]; l[now]=r[now]=val[now]=0; } void dfs(int u){ for(int i=first[u];i;i=next[i]){ int t=to[i]; dfs(t); siz[u] += siz[t] , sum[u] += sum[t]; rt[u] = Merge(rt[u],rt[t]); while(sum[u] > m) Pop(u); } siz[u]++; sum[u] += c[u]; val[u]=c[u]; rt[u] = Merge(u,rt[u]); while(sum[u] > m) Pop(u); ans = max(ans,(LL)w[u]*siz[u]); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d%d%d",&b[i],&c[i],&w[i]); add(b[i],i); } dfs(1); printf("%lld",ans); return 0; }