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

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

  • 相关阅读:
    Vue收集表单数据
    vcloak、vonce、vpre
    自定义指令总结
    vhtml指令
    Vue模板语法
    vtext指令与插值语法的区别
    Vue过滤器
    sharepoint获取文件的ICON
    Sharepoint中添加/编辑/删除Webpart的几种方法
    [转]客户端input file控件,C#多文件上传
  • 原文地址:https://www.cnblogs.com/yangsongyi/p/8921448.html
Copyright © 2020-2023  润新知