bzoj2809[Apio2012]dispatching

bzoj2809[Apio2012]dispatching

题意:

n个点组成一棵树,每个点都有一个领导力和费用,可以让一个点当领导,然后在这个点的子树中选择一些费用之和不超过m的点,得到领导的领导力乘选择的点的个数(领导可不被选择)的利润。求利润最大值。n≤100000

题解:

可并堆。可以得到一个结论,就是在子树中选点的时候,先选所有点,如果费用超了,就不断把费用最大的剔除,直到费用不超,这样得到的选点数量最大,这过程可以用堆维护。同时每个点的堆都可以由子树的堆合并得到,所以需要可并堆。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 100100
 6 #define ll long long
 7 using namespace std;
 8 
 9 int ch[maxn][2],rt[maxn],n,m,st; ll sz[maxn],v[maxn],ans,sm[maxn],gd[maxn];
10 struct e{int t,n;}; e es[maxn]; int ess,g[maxn];
11 void pe(int f,int t){es[++ess]=(e){t,g[f]}; g[f]=ess;}
12 void init(){ess=0; memset(g,0,sizeof(g));}
13 void update(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1; sm[x]=sm[ch[x][0]]+sm[ch[x][1]]+v[x];}
14 int merge(int x,int y){
15     if(!x||!y)return x+y; if(v[x]<v[y])swap(x,y); ch[x][1]=merge(ch[x][1],y);
16     swap(ch[x][0],ch[x][1]); update(x); return x;
17 }
18 void pop(int &x){
19     int y=merge(ch[x][0],ch[x][1]); ch[x][0]=ch[x][1]=0; sz[x]=1; sm[x]=v[x]; x=y;
20 }
21 void dfs(int x){
22     rt[x]=x; for(int i=g[x];i;i=es[i].n)dfs(es[i].t),rt[x]=merge(rt[x],rt[es[i].t]);
23     while(sz[rt[x]]&&sm[rt[x]]>m)pop(rt[x]); ans=max(ans,sz[rt[x]]*gd[x]);
24 }
25 int main(){
26     scanf("%d%d",&n,&m); init();
27     inc(i,1,n){
28         int a; ll b,c; scanf("%d%lld%lld",&a,&b,&c); if(a)pe(a,i);else st=i;
29         v[i]=sm[i]=b; sz[i]=1; gd[i]=c; ch[i][0]=ch[i][1]=rt[i]=0;
30     }
31     ans=0; dfs(st); printf("%lld",ans); return 0;
32 }

 

20160531

posted @ 2016-07-10 22:08  YuanZiming  阅读(900)  评论(0编辑  收藏  举报