zoukankan      html  css  js  c++  java
  • BZOJ_2809_[Apio2012]dispatching_可并堆

    BZOJ_2809_[Apio2012]dispatching_可并堆

    Description

    在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿。在这个帮派里,有一名忍者被称之为 Master。除了 Master以外,每名忍者都有且仅有一个上级。为保密,同时增强忍者们的领导力,所有与他们工作相关的指令总是由上级发送给他的直接下属,而不允许通过其他的方式发送。现在你要招募一批忍者,并把它们派遣给顾客。你需要为每个被派遣的忍者 支付一定的薪水,同时使得支付的薪水总额不超过你的预算。另外,为了发送指令,你需要选择一名忍者作为管理者,要求这个管理者可以向所有被派遣的忍者 发送指令,在发送指令时,任何忍者(不管是否被派遣)都可以作为消息的传递 人。管理者自己可以被派遣,也可以不被派遣。当然,如果管理者没有被排遣,就不需要支付管理者的薪水。你的目标是在预算内使顾客的满意度最大。这里定义顾客的满意度为派遣的忍者总数乘以管理者的领导力水平,其中每个忍者的领导力水平也是一定的。写一个程序,给定每一个忍者 i的上级 Bi,薪水Ci,领导力L i,以及支付给忍者们的薪水总预算 M,输出在预算内满足上述要求时顾客满意度的最大值。
    1  ≤N ≤ 100,000 忍者的个数;
    1  ≤M ≤ 1,000,000,000 薪水总预算; 
     
    0  ≤Bi < i  忍者的上级的编号;
    1  ≤Ci ≤ M                     忍者的薪水;
    1  ≤Li ≤ 1,000,000,000             忍者的领导力水平。

    Input

    从标准输入读入数据。
     
    第一行包含两个整数 N M,其中 N表示忍者的个数,M表示薪水的总预算。
     
    接下来 N行描述忍者们的上级、薪水以及领导力。其中的第 i 行包含三个整 Bi , C i , L i分别表示第i个忍者的上级,薪水以及领导力。Master满足B i = 0并且每一个忍者的老板的编号一定小于自己的编号 Bi < i

    Output

    输出一个数,表示在预算内顾客的满意度的最大值。

    Sample Input

    5 4
    0 3 3
    1 3 5
    2 2 2
    1 2 4
    2 3 1

    Sample Output

    6

    HINT

    如果我们选择编号为 1的忍者作为管理者并且派遣第三个和第四个忍者,薪水总和为 4,没有超过总预算                         4。因为派遣了                              2   个忍者并且管理者的领导力为      3,

    用户的满意度为 2      ,是可以得到的用户满意度的最大值。


    题目可以简化成这样:

    给出一棵 $n$ 个点以 $1$ 为根的有根树,每个点有代价 $ci$ 和价值 $Li$ 。对于某个点,从它子树中选出代价和不超过 $m$ 的一些点,可以获得 点数×当前点的价值 的收益。求最大收益。

    对于以每个点为根的子树,一定是优先选代价小的,并且尽可能的多选。

    每个节点维护一个可并堆(大根),从下至上合并,每次当总和大于$m$ 时弹出堆顶元素。

    为了方便每个点记录一下堆顶(左偏树的根)$root[x]$ 。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 100050
    typedef long long ll;
    int n,m,head[N],to[N<<1],nxt[N<<1],val[N],cnt,ls[N],rs[N],dis[N],siz[N];
    int rt,c[N],l[N],root[N];
    ll sum[N],ans;
    inline void add(int u,int v) {
    	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;	
    }
    int merge(int x,int y) {
    	if(!x) return y;
    	if(!y) return x;
    	if(c[x]<c[y]) swap(x,y);
    	rs[x]=merge(rs[x],y);
    	if(dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]);
    	dis[x]=dis[rs[x]]+1;
    	return x;
    }
    void dfs(int x) {
    	int i;
    	root[x]=x; sum[x]=c[x]; siz[x]=1;
    	for(i=head[x];i;i=nxt[i]) {
    		dfs(to[i]);
    		sum[x]+=sum[to[i]],siz[x]+=siz[to[i]],root[x]=merge(root[x],root[to[i]]);
    	}
    	while(sum[x]>m) {
    		sum[x]-=c[root[x]]; siz[x]--; root[x]=merge(ls[root[x]],rs[root[x]]);
    	}
    	ans=max(ans,1ll*l[x]*siz[x]);
    }
    int main() {
    	dis[0]=-1;
    	int i,x;
    	scanf("%d%d",&n,&m);
    	for(i=1;i<=n;i++) {
    		scanf("%d%d%d",&x,&c[i],&l[i]);
    		if(!x) rt=i;
    		else add(x,i);
    	}
    	dfs(rt);
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    HDU 5642 King's Order 动态规划
    HDU 5640 King's Cake GCD
    HDU 5641 King's Phone 模拟
    HDU 5299 Circles Game 博弈论 暴力
    HDU 5294 Tricks Device 网络流 最短路
    HDU 5289 Assignment rmq
    HDU 5288 OO’s Sequence 水题
    星际争霸 虚空之遗 人族5BB 操作流程
    Codeforces Beta Round #3 D. Least Cost Bracket Sequence 优先队列
    Codeforces Beta Round #3 C. Tic-tac-toe 模拟题
  • 原文地址:https://www.cnblogs.com/suika/p/8891288.html
Copyright © 2011-2022 走看看