bzoj2809 [Apio2012]dispatching
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2809
其实可以按照树的形状暴力枚举把谁当做管理者!
考虑到收益只和忍者个数有关,所以当薪水超限时把薪水最高的忍者去掉就行了。
这是一个大根堆。于是变成可并堆,用了左偏树。
第一次的左偏树。感觉写起来意外地简单。(虽然并不是1A)
#include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespace std; const int N=1e5+5; int n,head[N],c[N][2],dis[N],tot,rt[N],cnt[N],mas; ll lm,v[N],w[N],ans,sum[N],val[N]; struct Edge{ int next,to; Edge(int n=0,int t=0):next(n),to(t) {} }edge[N]; int rdn() { int ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch<='9'&&ch>='0')(ret*=10)+=ch-'0',ch=getchar(); return ret; } ll rdl() { ll ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch<='9'&&ch>='0')(ret*=10)+=ch-'0',ch=getchar(); return ret; } int merge(int x,int y) { if(!x)return y;if(!y)return x; if(val[x]<val[y])swap(x,y); c[x][1]=merge(c[x][1],y); if(dis[c[x][1]]>dis[c[x][0]])swap(c[x][1],c[x][0]); if(c[x][1])dis[x]=dis[c[x][1]]+1; sum[x]=sum[c[x][0]]+sum[c[x][1]]+val[x];//+val[x] cnt[x]=cnt[c[x][0]]+cnt[c[x][1]]+1;//+1 return x; } void dfs(int cr,int f) { rt[cr]=++tot;sum[tot]=val[tot]=v[cr];cnt[tot]=1; for(int i=head[cr],v;i;i=edge[i].next) if((v=edge[i].to)!=f) { dfs(v,cr);rt[cr]=merge(rt[cr],rt[v]); } while(sum[rt[cr]]>lm)rt[cr]=merge(c[rt[cr]][1],c[rt[cr]][0]); ans=max(ans,cnt[rt[cr]]*w[cr]); } int main() { n=rdn();lm=rdl(); for(int i=1;i<=n;i++) { int tp=rdn();edge[i]=Edge(head[tp],i);head[tp]=i; if(!tp)mas=i; v[i]=rdl();w[i]=rdl(); } dfs(mas,0);//mas不一定是1 printf("%lld",ans); return 0; }