P1552 [APIO2012] 派遣

题链 P1552 [APIO2012] 派遣

左偏树板子题,每个节点存储一个忍者集合的大根堆,保证和小于等于 \(M\) 的情况下忍者数量最多,每次向父亲合并计算一次答案,最后取 \(\max\) 即可,复杂度 \(O(n\log{n})\)

参考代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, f[N], root[N];
ll m, ans, lead[N], sz[N], sum[N];
struct Node {
    int l, r, dist;
    ll cost;
}tr[N];

bool cmp(int x, int y) {
    if (tr[x].cost != tr[y].cost) return tr[x].cost < tr[y].cost;
    return x < y;
}

int merge(int x, int y) {
    if (!x || !y) return x | y;
    if (cmp(x, y)) swap(x, y);
    tr[x].r = merge(tr[x].r, y);
    if (tr[tr[x].l].dist < tr[tr[x].r].dist) swap(tr[x].l, tr[x].r);
    tr[x].dist = tr[tr[x].r].dist + 1;
    return x;
}

void pop(int &x) {
    x = merge(tr[x].l, tr[x].r);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ ) {
        cin >> f[i] >> tr[i].cost >> lead[i];
        root[i] = merge(root[i], i);
        sum[i] = tr[i].cost, sz[i] = 1;
    }
    for (int i = n; i; i -- ) {
        while (m < sum[i]) sz[i] -- , sum[i] -= tr[root[i]].cost, pop(root[i]);
        ans = max(ans, sz[i] * lead[i]);
        if (i == 1) break;
        sz[f[i]] += sz[i], sum[f[i]] += sum[i];
        root[f[i]] = merge(root[i], root[f[i]]);
    }
    cout << ans << "\n";
    return 0;
}
posted @ 2025-03-04 16:18  YipChip  阅读(21)  评论(0)    收藏  举报