[APIO2012] 派遣

题目描述:

在树中找到一个点i,并且找到这个点子树中的一些点组成一个集合,使得集合中的所有点的c之和不超过M,且Li*集合中元素个数和最大。

题目分析:

首先贪心的想一下。
我们把i的子树及自己的元素全部排一下序,然后累加,去找最多的元素,sumc<=m
那么答案即为 Li*元素个数
那我们就可以枚举所有的点,每次都做一下这个过程,取max
如何快速从子树中得到信息呢?
对于这个排序,我们可以用可合并堆来搞.
每次把当前点堆与儿子堆合并,维护大根堆,然后pop最大元素,直到sumc<=m
这时ans=li*siz堆
堆合并logn
总的复杂度就是个 nlogn
注意开long long -_-

题目链接:

Luogu 1552

Ac 代码:

#include <iostream>
#include <cstdio>
#define int long long
const int maxm=110000; 
struct left_tree{
    int ls,rs;
    int dis,v;
    int sum,siz;
}st[maxm];
int rt[maxm],l[maxm],maxp,ans,n;
int head[maxm],to[maxm],net[maxm],cnt;
inline void addedge(int u,int v)
{
    cnt++;
    to[cnt]=v,net[cnt]=head[u],head[u]=cnt;
}
inline int merge(int x,int y)
{
    if(!x||!y) return x+y;
    if(st[x].v<st[y].v) std::swap(x,y);
    st[x].rs=merge(st[x].rs,y);
    if(st[st[x].ls].dis<st[st[x].rs].dis) std::swap(st[x].ls,st[x].rs);
    st[x].dis=st[st[x].rs].dis+1;
    st[x].sum=st[st[x].ls].sum+st[st[x].rs].sum+st[x].v;
    st[x].siz=st[st[x].ls].siz+st[st[x].rs].siz+1;
    return x;
}
inline int pop(int x)
{
    return merge(st[x].ls,st[x].rs);
}
void dfs(int now,int fa)
{
    for(int i=head[now];i;i=net[i])
    if(to[i]!=fa)
     dfs(to[i],now);
    for(int i=head[now];i;i=net[i])
    if(to[i]!=fa)
     rt[now]=merge(rt[now],rt[to[i]]);
    //printf("-%d %d %d-\n",now,st[rt[now]].v,st[rt[now]].sum);
    while(rt[now]&&st[rt[now]].sum>maxp)
     rt[now]=pop(rt[now]);
    ans=std::max(ans,l[now]*(st[rt[now]].siz));
}
main()
{
    scanf("%lld%lld",&n,&maxp);
    int root;
    for(int i=1;i<=n;i++)
    {
        int fa;
        scanf("%lld%lld%lld",&fa,&st[i].v,&l[i]);
        if(!fa) root=i;
        else addedge(fa,i);
        st[i].siz=1,st[i].sum=st[i].v;
        rt[i]=merge(rt[i],i);
    }
    dfs(root,0);
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值