zoukankan      html  css  js  c++  java
  • APIO2012 派遣

    题目描述

    题解:

    可并堆优化$dp$。

    由于$ans$只由$l$与派遣人数决定,我们可以贪心选取总和$<=m$的人。

    有两种选择,一种是维护小根堆,一直$pop$到弹出的总和$>m$;

    另一种是维护大根堆,一直$pop$到剩下总和$<=m$;

    这两种比较一定是维护大根堆更优,因为每次$pop$后剩下的堆可以直接回溯。

    然后$dp$就好了。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N = 100050;
    template<typename T>
    inline void read(T&x)
    {
        T f = 1,c = 0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
        x = f*c;
    }
    int n,b[N],c[N],hed[N],cnt,rt[N],dis[N],ls[N],rs[N],siz[N];
    ll m,l[N],ans=0,sum[N];
    struct EG
    {
        int to,nxt;
    }e[N];
    void ae(int f,int t)
    {
        e[++cnt].to = t;
        e[cnt].nxt = hed[f];
        hed[f] = cnt;
    }
    int merge(int x,int y)
    {
        if(!x||!y)return x+y;
        if(c[x]<c[y])swap(x,y);
        rs[x] = merge(rs[x],y);
        if(dis[ls[x]]<dis[rs[x]])swap(ls[x],rs[x]);
        dis[x] = dis[rs[x]]+1;
        return x;
    }
    int pop(int x)
    {
        return merge(ls[x],rs[x]);
    }
    struct Pair
    {
        int x;
        ll w;
        Pair(){}
        Pair(int x,ll w):x(x),w(w){}
        friend bool operator < (Pair a,Pair b)
        {
            return a.w < b.w;
        }
    };
    int cal(int u)
    {
        while(sum[u]>m)
        {
            sum[u]-=c[rt[u]];
            rt[u]=pop(rt[u]);
            siz[u]--;
        }
        return siz[u];
    }
    void dfs(int u)
    {
        siz[u]=1;sum[u]=c[u];
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            dfs(to);
            siz[u]+=siz[to];
            sum[u]+=sum[to];
            rt[u] = merge(rt[u],rt[to]);
        }
        ans = max(ans,l[u]*cal(u));
    }
    int main()
    {
        read(n),read(m);
        for(int i=1;i<=n;i++)
        {
            read(b[i]),read(c[i]),read(l[i]);
            ae(b[i],i);
            rt[i]=i,dis[i]=1;
        }
        dfs(1);
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    .net实现支付宝在线支付
    彻头彻尾理解单例模式与多线程
    Linq中的Select与Select many
    MVC中子页面如何引用模板页中的jquery脚本
    浅谈MemCahe
    左连接,右连接,内连接(left join ,right join,inner join)
    协变与逆变
    子类对父类中的属性和字段的改写
    里氏转换
    MVC基础篇—控制器与视图数据的传递
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10294989.html
Copyright © 2011-2022 走看看