標籤:can 滿意度 最大 roo 傳遞 type 輸入輸出格式 總數 超過
題目背景
在一個忍者的幫派裡,一些忍者們被選中派遣給顧客,然後依據自己的工作擷取報償。
題目描述
在這個幫派裡,有一名忍者被稱之為Master。除了Master以外,每名忍者都有且僅有一個上級。為保密,同時增強忍者們的領導力,所有與他們工作相關的指令總是由上級發送給他的直屬員工,而不允許通過其他的方式發送。
現在你要招募一批忍者,並把它們派遣給顧客。你需要為每個被派遣的忍者支付一定的薪水,同時使得支付的薪水總額不超過你的預算。另外,為了發送指令,你需要選擇一名忍者作為管理者,要求這個管理者可以向所有被派遣的忍者發送指令,在發送指令時,任何忍者(不管是否被派遣)都可以作為訊息的傳遞人。管理者自己可以被派遣,也可以不被派遣。當然,如果管理者沒有被排遣,你就不需要支付管理者的薪水。
你的目標是在預算內使顧客的滿意度最大。這裡定義顧客的滿意度為派遣的忍者總數乘以管理者的領導力水平,其中每個忍者的領導力水平也是一定的。
寫一個程式,給定每一個忍者i的上級Bi,薪水Ci,領導力Li,以及支付給忍者們的薪水總預算M,輸出在預算內滿足上述要求時顧客滿意度的最大值。
輸入輸出格式輸入格式:
第一行包含兩個整數N和M,其中N表示忍者的個數,M表示薪水的總預算。
接下來N行描述忍者們的上級、薪水以及領導力。其中的第i行包含三個整數Bi,Ci,Li分別表示第i個忍者的上級,薪水以及領導力。Master滿足Bi=0,並且每一個忍者的老闆的編號一定小於自己的編號Bi<i。
輸出格式:
輸出一個數,表示在預算內顧客的滿意度的最大值。
輸入輸出範例輸入範例#1:
5 40 3 31 3 52 2 21 2 42 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。
蜜汁MLE...仍然不知道我為什麼把一個函數刪了之後就AC了..好迷...
我們在每個點維護一個左偏樹, 對這個樹進行dfs, 回溯的時候合并它和父親的左偏樹。
我們的左偏樹是一個大根堆,因為如果我們在一個點上的左偏樹裡的左右的值得和大於m,我們就必須刪掉一些點。
而我們刪掉價值更大的點,就可以保留更多的點。
所以知道左偏樹的值得和小於m,我們不停的del它的根,同時siz-1,然後這個點的答案就是L[x] * siz[x].
對於所有的答案取max就行了。
#include <iostream>#include <cstdio>#include<cstdlib>using namespace std;#define N 100005typedef long long ll;int n;ll m;struct edge{ int nxt, to;}ed[N];int head[N], cnt;inline void add(int x, int y){ ed[++cnt] = (edge){head[x], y}; head[x] = cnt;}int ch[N][2], root[N], sz[N];int R;ll sum[N], dis[N], val[N], L[N];ll ans;int Merge(int x, int y){ if (x * y == 0) return x + y; if (val[x] < val[y]) swap(x, y);//大根堆 ch[x][1] = Merge(ch[x][1], y); if (dis[ch[x][0]] < dis[ch[x][1]]) swap(ch[x][0], ch[x][1]); dis[x] = dis[ch[x][1]] + 1; return x;}inline void del(int x){ val[x] = -1; root[x] = Merge(ch[x][0], ch[x][1]);}//del這個函數我手寫在dfs裡就A了,仍然不知道為何,求大神指點,萬分感謝void dfs(int x){ root[x] = x, sum[x] = val[x], sz[x] = 1; for (int i = head[x] ; i ; i = ed[i].nxt) { int to = ed[i].to; dfs(to); sum[x] += sum[to], sz[x] += sz[to]; root[x] = Merge(root[x], root[to]) ; } while(sum[x] > m and sz[x]) { sum[x] -= val[root[x]]; root[x] = Merge(ch[root[x]][0], ch[root[x]][1]); sz[x]--; } ans = max(ans, L[x] * sz[x]);}signed main(){ scanf("%d%lld", &n, &m); for (int i = 1 ; i <= n ; i ++) { int x; scanf("%d%lld%lld", &x, &val[i], &L[i]); if (!x) R = i; add(x, i); } dfs(R); cout << ans << endl; return 0;}
[APIO2012]派遣