zoukankan      html  css  js  c++  java
  • 派遣「APIO2012」(左偏树)

    显然这种上下级的关系构成一个树形结构。

    我们可以枚举一个管理者,然后再来看看他的满意度水平到底有多高。

    因为要求这个管理者可以向所有人发送指令,所以他只能选他的子树中的点。

    把他所有选的人放在同一个集合内,要求总薪水小于M且人数最多(因为满意度只和人数和管理者的领导力有关)。

    那我们就得到一个思路:把所有子树内的人放到一个集合里,然后如果总薪水大于M,就把薪水最大的人干掉,直到薪水小于M。

    如果这个集合是个堆就可以在$O(1)$的复杂度内找到薪水最大的人,并在$O(log{n})$的复杂度内干掉他。

    可是这样做总复杂度是$O(n^2)$还是太慢。

    考虑优化。

    我们发现每个人最终的集合和它的孩子的集合是有大部分重复的,用线段树合并的思想,我们可以把他的儿子的集合并到他的上面。

    这就要用到可并堆了(这里用左偏树)。

    然后就可以在$O(nlog{n})$的复杂度内解决问题了。

    具体实现的时候维护一个size和一个sum分别代表一个人的集合的大小和总薪水。

    再维护一个root代表堆顶。

    这是树上左偏树的基本套路。

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    const ll N = 100010;
    struct Leftist_Tree{
        ll dist, val, ls, rs;
    }tr[N];
    struct node{
        ll pre, to;
    }edge[N << 1];
    ll head[N], tot;
    ll n, m;
    ll c[N], w[N], ans;
    ll rt[N], sum[N], sz[N];
    void add(ll u, ll v) {
        edge[++tot] = node{head[u], v};
        head[u] = tot;
    }
    ll Merge(ll u, ll v) {
        if (!u || !v) return u | v;
        if (tr[u].val < tr[v].val) swap(u, v);
        tr[u].rs = Merge(tr[u].rs, v);
        if (tr[tr[u].ls].dist < tr[tr[u].rs].dist) swap(tr[u].ls, tr[u].rs);
        tr[u].dist = tr[tr[u].rs].dist + 1;
        return u;
    }
    void dfs(ll x, ll fa) {
        for (ll i = head[x]; i; i = edge[i].pre) {
            ll y = edge[i].to;
            if (y == fa) continue;
            dfs(y, x);
            rt[x] = Merge(rt[x], rt[y]);
            sum[x] += sum[y];
            sz[x] += sz[y];
        }
        while (sum[x] > m && sz[x]) {
            sum[x] -= tr[rt[x]].val;
            rt[x] = Merge(tr[rt[x]].ls, tr[rt[x]].rs);
            sz[x]--;
        }
        ans = max(ans, sz[x] * w[x]);
    }
    int main() {
        cin >> n >> m;
        for (ll i = 1; i <= n; i++) {
            ll b;
            cin >> b >> c[i] >> w[i];
            if (b != 0) {
                add(b, i);
                add(i, b);
            }
            rt[i] = i;
            tr[i].ls = tr[i].rs = tr[i].dist = 0;
            tr[i].val = sum[i] = c[i];
            sz[i] = 1;
        }
        dfs(1, 0);
        cout << ans;
        return 0;
    }
  • 相关阅读:
    三.Python数据类型详述
    二.Python基础语法和数据类型
    一.Python特点
    Hive之explode和lateral view
    javascript之函数作用域
    javascript之函数使用
    javascript之函数定义
    javascript之变量
    Html之元素
    Html之页面
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12864133.html
Copyright © 2011-2022 走看看