洛谷 [P1552] 派遣

树型DP + 可并堆

非常清楚的想到是树型DP, 但是如何维护最小值, 于是就去新学了可并堆

#include 
#include 
#include 
#include 
#include 
#define ll long long
using namespace std;
const int MAXN = 100005;
ll init() {
    ll rv = 0, fh = 1;
    char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') fh = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        rv = (rv<<1) + (rv<<3) + c - '0';
        c = getchar();
    }
    return fh * rv;
}
struct edge{
    int to, nxt;
}e[MAXN << 1];
int n, m, head[MAXN], nume, rot, fa[MAXN], id[MAXN];
ll ans, wei[MAXN], mon[MAXN], siz[MAXN], sum[MAXN]; 
void adde(int from, int to) {
    e[++nume].to = to;
    e[nume].nxt = head[from];
    head[from] = nume;
}
struct LT{
    struct node{
        int l, r;
        ll val, dist;
    }a[MAXN];
    int merge(int u, int v) {
        if(!u || !v) return u + v;
        if(a[u].val < a[v].val) swap(u, v);
        int &ur = a[u].r, &ul = a[u].l;
        ur = merge(ur, v);
        if(a[ul].dist < a[ur].dist) swap(ul, ur);
        a[u].dist = a[ur].dist + 1;
        return u;
    }
    void erase(int &u) {
        u = merge(a[u].l, a[u].r);
    }
}lt;
void dfs(int u) {
    id[u] = u;
    siz[u] = 1;
    sum[u] = mon[u];
    lt.a[u].val = mon[u];
    for(int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        dfs(v);
        sum[u] += sum[v];
        siz[u] += siz[v];
        id[u] = lt.merge(id[u], id[v]);
    }
    while(sum[u] > m && siz[u]) {
        siz[u]--;
        sum[u] -= lt.a[id[u]].val;
        lt.erase(id[u]);
    }
    ans = max(ans, siz[u] * wei[u]);
}
int main() {
    n = init(); m = init();
    for(int i = 1; i <= n; i++) {
        fa[i] = init();
        if(fa[i]) adde(fa[i], i);
        else rot = i;
        mon[i] = init(); wei[i] = init();
    }
    dfs(rot);
    /*for(int i = 1; i <= n; i++) {
        printf("%lld %lld\n", siz[i], sum[i]);
    }*/
    cout << ans << endl;
    return 0;
}

转载于:https://www.cnblogs.com/Mr-WolframsMgcBox/p/8964527.html

你可能感兴趣的:(洛谷 [P1552] 派遣)