1. 程式人生 > >[luogu P1552] [APIO2012]派遣

[luogu P1552] [APIO2012]派遣

return 忍者 amp 們的 給定 master getc 包含 spa

[luogu P1552] [APIO2012]派遣

題目背景

在一個忍者的幫派裏,一些忍者們被選中派遣給顧客,然後依據自己的工作獲取報償。

題目描述

在這個幫派裏,有一名忍者被稱之為Master。除了Master以外,每名忍者都有且僅有一個上級。為保密,同時增強忍者們的領導力,所有與他們工作相關的指令總是由上級發送給他的直接下屬,而不允許通過其他的方式發送。

現在你要招募一批忍者,並把它們派遣給顧客。你需要為每個被派遣的忍者支付一定的薪水,同時使得支付的薪水總額不超過你的預算。另外,為了發送指令,你需要選擇一名忍者作為管理者,要求這個管理者可以向所有被派遣的忍者發送指令,在發送指令時,任何忍者(不管是否被派遣)都可以作為消息的傳遞人。管理者自己可以被派遣,也可以不被派遣。當然,如果管理者沒有被排遣,你就不需要支付管理者的薪水。

你的目標是在預算內使顧客的滿意度最大。這裏定義顧客的滿意度為派遣的忍者總數乘以管理者的領導力水平,其中每個忍者的領導力水平也是一定的。

寫一個程序,給定每一個忍者i的上級Bi,薪水Ci,領導力Li,以及支付給忍者們的薪水總預算M,輸出在預算內滿足上述要求時顧客滿意度的最大值。

輸入輸出格式

輸入格式:

第一行包含兩個整數N和M,其中N表示忍者的個數,M表示薪水的總預算。

接下來N行描述忍者們的上級、薪水以及領導力。其中的第i行包含三個整數Bi,Ci,Li分別表示第i個忍者的上級,薪水以及領導力。Master滿足Bi=0,並且每一個忍者的老板的編號一定小於自己的編號Bi<i。

輸出格式:

輸出一個數,表示在預算內顧客的滿意度的最大值。

輸入輸出樣例

輸入樣例#1:
5 4
0 3 3
1 3 5
2 2 2
1 2 4
2 3 1
輸出樣例#1:
6

說明

1 ≤ N ≤ 100,000 忍者的個數;

1 ≤ M ≤ 1,000,000,000 薪水總預算;

0 ≤ Bi < i 忍者的上級的編號;

1 ≤ Ci ≤ M 忍者的薪水;

1 ≤ Li ≤ 1,000,000,000 忍者的領導力水平。

對於 30%的數據,N ≤ 3000。

想了較長時間(其實是腦子壞了)。

我最初的想法就是,我們可以定住一個點x,將它當做是管理者,然後那些被派遣的人從以其為根的子樹中找。

然後ans=max(ans,lead[x]*calc(x))。顯然,這是正確的吧。因為管理者需要能到達所有的被派遣者,及管理者是被選出子樹的根節點。

這樣方便了我們calc(其實就是運用了一點點的動規思想和貪心思想)。

那麽,calc怎麽辦?也就是說,我們要在x的幾棵子樹中(包括自己)找到最多的點代價和不超過m。

想到了什麽?左偏樹好像可以。

就是說,對於每一個點x,都連著好幾棵處理好的左偏樹,然後我們可以用log的時間合並。

但是,我們還要刪掉一些點使滿足條件。我選擇了用大根堆,這樣刪除方便。

但是這個操作具體的復雜度是多少呢?由於刪除的點不會重新被加入,所以每個點最多被刪除一次,復雜度為nlogn。

加上上面的一系列操作nlogn的復雜度,總復雜度依然是nlogn。

code:

技術分享
 1 %:pragma GCC optimize(2)
 2 #include<bits/stdc++.h>
 3 #define LL long long
 4 using namespace std;
 5 const int N=100005;
 6 vector <int> son[N];
 7 int n,m,ro[N]; LL s[N],c[N],f[N],ans;
 8 struct lft {int l,r,d,w; void cl() {l=r=d=0;}}a[N];
 9 inline int read() {
10     int x=0; char ch=getchar();
11     while (ch<0||ch>9) ch=getchar();
12     while (ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar();
13     return x;
14 }
15 int merge(int x,int y) {
16     if (!x||!y) return x+y; if (a[x].w<a[y].w) swap(x,y);
17     a[x].r=merge(a[x].r,y); int l=a[x].l,r=a[x].r;
18     if (a[l].d<a[r].d) swap(a[x].l,a[x].r);
19     a[x].d=a[a[x].r].d+1;
20     return x;
21 }
22 int main() {
23     n=read(),m=read(),ans=0,a[0].d=-1;
24     for (int i=1; i<=n; i++) {
25         a[i].cl(),ro[i]=i,son[read()].push_back(i);
26         s[i]=a[i].w=read(),c[i]=1,f[i]=read();
27     }
28     for (int i=n,siz; i>=1; i--) {
29         siz=son[i].size();
30         for (int k=0,j; k<siz; k++) {
31             j=son[i][k],ro[i]=merge(ro[i],ro[j]);
32             s[i]+=s[j],c[i]+=c[j];
33         }
34         for (; s[i]>m;) {
35             s[i]-=a[ro[i]].w,c[i]--;
36             ro[i]=merge(a[ro[i]].l,a[ro[i]].r);
37         }
38         ans=max(ans,f[i]*c[i]);
39     }
40     printf("%lld\n",ans);
41     return 0;
42 }
View Code

[luogu P1552] [APIO2012]派遣