Problem
【APIO2012】Dispatching
TimeLimit:10Sec
MemoryLimit:128MB
Description
在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿。
在这个帮派里,有一名忍者被称之为Master。除了Master以外,每名忍者都有且仅有一个上级。为保密,同时增强忍者们的领导力,所有与他们工作相关的指令总是由上级发送给他的直接下属,而不允许通过其他的方式发送。
现在你要招募一批忍者,并把它们派遣给顾客。你需要为每个被派遣的忍者支付一定的薪水,同时使得支付的薪水总额不超过你的预算。另外,为了发送指令,你需要选择一名忍者作为管理者,要求这个管理者可以向所有被派遣的忍者发送指令,在发送指令时,任何忍者(不管是否被派遣)都可以作为消息的传递人。管理者自己可以被派遣,也可以不被派遣。当然,如果管理者没有被排遣,就不需要支付管理者的薪水。你的目标是在预算内使顾客的满意度最大。
这里定义顾客的满意度为派遣的忍者总数乘以管理者的领导力水平,其中每个忍者的领导力水平也是一定的。
写一个程序,给定每一个忍者i的上级Bi,薪水Ci,领导力Li,以及支付给忍者们的薪水总预算M,输出在预算内满足上述要求时顾客满意度的最大值。
从标准输入读入数据。
第一行包含两个整数N和M,其中N表示忍者的个数,M表示薪水的总预算。
接下来N行描述忍者们的上级、薪水以及领导力。其中的第i行包含三个整数Bi,Ci,Li分别表示第i个忍者的上级,薪水以及领导力。Master满足Bi=0,并且每一个忍者的老板的编号一定小于自己的编号。
Output
输出一个数,表示在预算内顾客的满意度的最大值。
1 2 3 4 5 6
| 5 4 0 3 3 1 3 5 2 2 2 1 2 4 2 3 1
|
Sample Output
Hint
样例解释
如果我们选择编号为1的忍者作为管理者并且派遣第三个和第四个忍者,薪水总和为4,没有超过总预算4。
因为派遣了2个忍者并且管理者的领导力为3,用户的满意度为6,是可以得到的用户满意度的最大值。
数据范围
1≤N≤105,1≤M≤109,0≤Bi<i,1≤Ci≤M,1≤Li≤109
标签:可并堆
左偏树
Solution
可并堆基础题。
对于每个结点作领导的情况,贪心策略肯定在其子树中从小往大选,直到选不了为止。可以每个结点用一个堆维护,但遍历子树会导致复杂度爆炸。
考虑每次用已经算出的一些结点的答案。那么可以想到一种做法:
将每个结点子树中的所有点默认先选上,再从大往小去掉直到可行为止。这样在儿子结点中都没选到的点一定不会在父节点中选到。于是可以直接将每个结点最后选出的点加入到父亲的备选点集中。这样不难发现可以用可并堆维护,DFS时将所有儿子结点的可并堆并起来,再从大往小pop点,找到可行最大size后更新答案即可。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| #include <bits/stdc++.h> #define MAX_N 100000 using namespace std; typedef long long lnt; template <class T> inline void read(T &x) { x = 0; int c = getchar(), f = 1; for (; !isdigit(c); c = getchar()) if (c == 45) f = -1; for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0'); } struct node {int c, d, ls, rs;} h[MAX_N+5]; int n, m, b[MAX_N+5], c[MAX_N+5], l[MAX_N+5], sz[MAX_N+5]; vector <int> G[MAX_N+5]; int fa[MAX_N+5]; lnt mx, s[MAX_N+5]; int getf(int x) {return fa[x] == x ? fa[x] : getf(fa[x]);} int merge(int a, int b) { if (!a || !b) return a^b; if (h[a].c < h[b].c) swap(a, b); h[a].rs = merge(h[a].rs, b), fa[h[a].rs] = a; if (h[h[a].rs].d > h[h[a].ls].d) swap(h[a].ls, h[a].rs); h[a].d = h[a].rs ? h[h[a].rs].d+1 : 0; return a; } int pop(int a) { int l = h[a].ls, r = h[a].rs; h[a].ls = h[a].rs = h[a].c = 0; return fa[l] = l, fa[r] = r, merge(l, r); } int DFS(int u) { int rt = u; s[u] = c[u], sz[u] = 1; for (int i = 0, v; i < (int)G[u].size(); i++) rt = merge(rt, DFS(v = G[u][i])), s[u] += s[v], sz[u] += sz[v]; while (s[u] > m && sz[u]) s[u] -= h[rt].c, sz[u]--, rt = pop(rt); return mx = max(mx, 1LL*sz[u]*l[u]), rt; } int main() { read(n), read(m); for (int i = 1; i <= n; i++) read(b[i]), read(c[i]), read(l[i]); for (int i = 1; i <= n; i++) G[b[i]].push_back(i); for (int i = 1; i <= n; i++) fa[i] = i, h[i].c = c[i]; return DFS(1), printf("%lld\n", mx), 0; }
|