BZOJ 2809 [Apio2012]dispatching

可并堆

如果固定了管理者,那一定是贪心地选取子树内最小的若干个。因此用大根堆维护子树值,满足总和小于m,然后合并给父亲。

#include<cstdio>
#include<algorithm>
#define N 100005
#define ll long long
using namespace std;
namespace runzhe2000
{
    int n, m, fa[N], mon[N], abi[N], root[N];
    ll ans;

    struct heap // big root
    {
        int ch[2]; ll v; int dis; ll sum; int cnt;
    }h[N];
    int merge(int x, int y)
    {
        if(!x)return y; if(!y)return x;
        if(h[x].v < h[y].v) swap(x, y);
        h[x].ch[1] = merge(h[x].ch[1], y); 
        if(h[h[x].ch[0]].dis < h[h[x].ch[1]].dis) swap(h[x].ch[0], h[x].ch[1]);
        h[x].dis = h[h[x].ch[1]].dis + 1;
        h[x].sum = h[x].v + h[h[x].ch[0]].sum + h[h[x].ch[1]].sum;
        h[x].cnt = 1 + h[h[x].ch[0]].cnt + h[h[x].ch[1]].cnt;
        return x;
    }
    int pop(int x){return merge(h[x].ch[0], h[x].ch[1]);}

    void main()
    {
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d%d",&fa[i],&mon[i],&abi[i]);
            root[i] = i;
            h[i] = (heap){{0,0},mon[i],0,mon[i],1};
        }
        for(int i = n; i; i--)
        {
            while(h[root[i]].sum > m) root[i] = pop(root[i]);
            ll tmp = (ll)h[root[i]].cnt * abi[i];
            ans = max(ans, tmp);
            root[fa[i]] = merge(root[fa[i]], root[i]) ;
        }
        printf("%lld\n",ans);
    }
}
int main()
{
    runzhe2000::main();
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值