「Luogu P1552 && BZOJ 2809」[APIO2012] 派遣

现在你要招募一批忍者,并把它们派遣给顾客。你需要为每个被派遣的忍者支付一定的薪水,同时使得支付的薪水总额不超过你的预算。另外,为了发送指令,你需要选择一名忍者作为管理者,要求这个管理者可以向所有被派遣的忍者发送指令,在发送指令时,任何忍者(不管是否被派遣)都可以作为消息的传递人。管理者自己可以被派遣,也可以不被派遣。当然,如果管理者没有被排遣,你就不需要支付管理者的薪水。

你的目标是在预算内使顾客的满意度最大。这里定义顾客的满意度为派遣的忍者总数乘以管理者的领导力水平,其中每个忍者的领导力水平也是一定的。

写一个程序,给定每一个忍者 i 的上级 Bi ,薪水 Ci ,领导力 Li ,以及支付给忍者们的薪水总预算 M ,输出在预算内满足上述要求时顾客满意度的最大值。

Luogu

BZOJ

分析

首先根据上级与下级之间的关系,我们可以建出一棵树,然后我们想要知道以每个忍者作为管理者顾客满意度的最大值。显然以 u 作为管理者,能够派遣的忍者一定在它的子树中,我们可以 dfs 递归求出,维护一个左偏树,利用它大根堆和可合并的性质,首先将它的子节点的堆合并,同时统计总共的薪水和人数,然后如果薪水超过预算,我们每次去掉堆顶,也就是去掉最贵的忍者,然后求出满意度取 max 。

代码

//=========================
//  author:hliwen
//  date:2020.1.18
//=========================
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100005
#define il inline
#define re register
#define DEBUG puts("ok")
#define tie0 cin.tie(0),cout.tie(0)
#define fastio ios::sync_with_stdio(false)
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
typedef long long ll;

template <typename T> inline void read(T &x) {
    T f = 1; x = 0; char c;
    for (c = getchar(); !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    x *= f;
}

ll ans;
int n, m, Master;
ll sum[N], val[N], l[N];
int tot[N], rs[N], ls[N], dis[N];
int to[N], nxt[N], head[N], cnt;

void insert(int u, int v) {
    to[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
}

int merge(int x, int y) {
    if (!x || !y) return x + y;
    if (val[x] < val[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;
}

int pop(int x) {
    return merge(ls[x], rs[x]);
}

int dfs(int u) {
    int x = u, v;
    sum[u] = val[u], tot[u] = 1;
    for (int i = head[u]; i; i = nxt[i]) {
        v = to[i];
        int y = dfs(v);
        x = merge(x, y);
        sum[u] += sum[v], tot[u] += tot[v];
    }
    while (sum[u] > m) {
        sum[u] -= val[x], tot[u] --;
        x = pop(x);
    }
    ans = max(ans, tot[u] * l[u]);
    return x;
}

int main() {
    int x;
    read(n), read(m);
    for (int i = 1; i <= n; ++i) {
        read(x), read(val[i]), read(l[i]);
        if (!x) Master = i;
        else insert(x, i);
    }
    dfs(Master);
    printf("%lld", ans);
    return 0;
}

「Luogu P1552 && BZOJ 2809」[APIO2012] 派遣

上一篇:linux下后台运行程序


下一篇:Linux安装nginx