[APIO2012]派遣

[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\n",ans);
}

  有不理解的地方,可以发评论,我会解答

posted @ 2018-04-23 20:00  Yang1208  阅读(460)  评论(0编辑  收藏  举报