bzoj2809 [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,是可以得到的用戶滿意度的最大值。


正解:左偏樹

dfs遍歷每個結點,在回溯時合併這個點及它的所有兒子。對於每個集合維護一個大根堆的左偏樹,當一棵樹內薪水之和大於m時就刪除根節點,對於每顆樹取一個最大的size*lead。


//It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf 1<<30
#define il inline
#define RG register
#define ull unsigned long long
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)

using namespace std;

struct left_tree{
    int ls,rs,dis,size;
    ull key,tot;
}ltree[100010];

struct edge{ int nt,to; }g[200010];

int head[100010],lead[100010],n,m,num;
ull ans;

il int gi(){
    RG int x=0,q=0; RG char ch=getchar();
    while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if (ch=='-') q=1,ch=getchar();
    while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q ? -x : x;
}

il void insert(RG int from,RG int to){ g[++num]=(edge){head[from],to},head[from]=num; return; }

il void build(RG int x,RG int k){ ltree[x]=(left_tree){0,0,0,1,(ull)k,(ull)k}; return; }

il int merge(RG int x,RG int y){
    if (!x) return y; if (!y) return x; if (ltree[x].key<ltree[y].key) swap(x,y);
    ltree[x].rs=merge(ltree[x].rs,y); RG int &l=ltree[x].ls,&r=ltree[x].rs;
    ltree[x].tot=ltree[l].tot+ltree[r].tot+ltree[x].key,ltree[x].size=ltree[l].size+ltree[r].size+1;
    if (ltree[l].dis<ltree[r].dis) swap(l,r); if (!r) ltree[x].dis=0; else ltree[x].dis=ltree[r].dis+1;
    return x;
}

il int dfs(RG int x){
    RG int rt=x; for (RG int i=head[x];i;i=g[i].nt) rt=merge(rt,dfs(g[i].to));
    while (ltree[rt].tot>(ull)m) rt=merge(ltree[rt].ls,ltree[rt].rs);
    ans=max(ans,(ull)ltree[rt].size*(ull)lead[x]); return rt;
}

il void work(){
    n=gi(),m=gi(); RG int f,c;
    for (RG int i=1;i<=n;++i) f=gi(),c=gi(),lead[i]=gi(),build(i,c),insert(f,i);
    dfs(1); printf("%llu",ans); return;
}

int main(){
    File("dispatching");
    work();
    return 0;
}

發佈了49 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章