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;
}

浙公网安备 33010602011771号