[Apio2012]dispatching 左偏树做法
http://codevs.cn/problem/1763/
维护子树大根堆,当子树薪水和>m时,删除最贵的点
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; int n,m; #define N 100001 int lc[N],rc[N]; int key[N],dis[N]; int fa[N],siz[N],lead[N],money[N]; LL sum[N],ans; int tot,nxt[N],to[N],front[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; } int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); } int merge(int a,int b) { if(!a || !b) return a+b; if(money[a]<money[b]) swap(a,b); rc[a]=merge(rc[a],b); siz[a]=1+siz[lc[a]]+siz[rc[a]]; sum[a]=money[a]+sum[lc[a]]+sum[rc[a]]; if(dis[rc[a]]>dis[lc[a]]) swap(rc[a],lc[a]); if(!rc[a]) dis[a]=0; else dis[a]=dis[rc[a]]+1; return a; } void erase(int x) { fa[x]=merge(lc[x],rc[x]); fa[fa[x]]=fa[x]; } void dfs(int x) { for(int i=front[x];i;i=nxt[i]) { dfs(to[i]); int u=find(to[i]),v=find(x); int w=merge(u,v); fa[u]=fa[v]=w; fa[w]=w; while(sum[w]>m) erase(w),w=fa[w]; } ans=max(ans,(LL)lead[x]*siz[find(x)]); } int main() { read(n); read(m); int f,rt; for(int i=1;i<=n;++i) { read(f); if(f) add(f,i); else rt=i; read(money[i]); read(lead[i]); fa[i]=i; siz[i]=1; sum[i]=money[i]; } dfs(rt); cout<<ans; }