[APIO2012]派遣
题目描述
在这个帮派里,有一名忍者被称之为Master。除了Master以外,每名忍者都有且仅有一个上级。为保密,同时增强忍者们的领导力,所有与他们工作相关的指令总是由上级发送给他的直接下属,而不允许通过其他的方式发送。
现在你要招募一批忍者,并把它们派遣给顾客。你需要为每个被派遣的忍者支付一定的薪水,同时使得支付的薪水总额不超过你的预算。另外,为了发送指令,你需要选择一名忍者作为管理者,要求这个管理者可以向所有被派遣的忍者发送指令,在发送指令时,任何忍者(不管是否被派遣)都可以作为消息的传递人。管理者自己可以被派遣,也可以不被派遣。当然,如果管理者没有被排遣,你就不需要支付管理者的薪水。
你的目标是在预算内使顾客的满意度最大。这里定义顾客的满意度为派遣的忍者总数乘以管理者的领导力水平,其中每个忍者的领导力水平也是一定的。
写一个程序,给定每一个忍者i的上级Bi,薪水Ci,领导力Li,以及支付给忍者们的薪水总预算M,输出在预算内满足上述要求时顾客满意度的最大值。
输入输出格式
输入格式:
第一行包含两个整数N和M,其中N表示忍者的个数,M表示薪水的总预算。
接下来N行描述忍者们的上级、薪水以及领导力。其中的第i行包含三个整数Bi,Ci,Li分别表示第i个忍者的上级,薪水以及领导力。Master满足Bi=0,并且每一个忍者的老板的编号一定小于自己的编号Bi<i。
输出格式:
输出一个数,表示在预算内顾客的满意度的最大值。
输入输出样例
输入样例: 5 4 0 3 3 1 3 5 2 2 2 1 2 4 2 3 1
输出样例: 6
思路
这道题比较明显是可并堆,首先我们来读题,题目中说,我们要求出最大的满意值。首先来分析对于一名指定的忍者当做master的时候,他的能力值是一定的,要想最大,忍者的个数就一定要最多,那么我们就要挑选薪水最少的忍者来执行任务,如果分析到这种程度,问题就变得开朗许多。我们可以维护一个可并大根堆,并在维护这个堆的同时,维护堆内所有忍者的薪水和以及忍者个数,如果薪水和大于预算的值,弹出最大的值(堆顶元素),就可以了,由于关系满足一棵树,我们从下到上维护就可以了,是不是比较简单?
代码
#include <stdio.h> int n,m; int val[100001]; int cost[100001]; int head[100001]; int to[100001]; int nxt[100001]; int dis[100001]; int many[100001]; int lson[100001]; int rson[100001]; long long sum[100001]; int idx,root; long long ans; long long max(long long a,long long b) { return (a<b)?b:a; } void swap(int &a,int &b) { a+=b,b=a-b,a-=b; } void add(int x,int y) { nxt[++idx]=head[x]; head[x]=idx; to[idx]=y; } int merge(int x,int y) { if(!x) return y; if(!y) return x; if(cost[x]<cost[y]) swap(x,y); rson[x]=merge(rson[x],y); if(dis[rson[x]]>dis[lson[x]]) swap(rson[x],lson[x]); dis[x]=dis[rson[x]]+1; sum[x]=cost[x]+sum[lson[x]]+sum[rson[x]]; many[x]=many[rson[x]]+many[lson[x]]+1; return x; } int check(int p) { while(sum[p]>m) { long long tmp=sum[p]-cost[p]; int tmp2=many[p]; p=merge(lson[p],rson[p]); sum[p]=tmp,many[p]=tmp2-1; } return p; } int dfs(int p) { int head1=p,tmp=0; for(int i=head[p];i;i=nxt[i]) tmp=dfs(to[i]),head1=merge(head1,tmp); head1=check(head1); ans=max(ans,((long long)many[head1]*val[p])); return head1; } int main() { dis[0]=-1; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int a; scanf("%d%d%d",&a,&cost[i],&val[i]); if(a) add(a,i); else root=i; } for(int i=1;i<=n;i++) many[i]=1,sum[i]=cost[i]; dfs(root); printf("%lld ",ans); }
有不理解的地方,可以发评论,我会解答