zoukankan      html  css  js  c++  java
  • 【bzoj2809】[Apio2012]dispatching (左偏树)

    我们需要枚举根,然后从其子树内选尽量多的点,薪水不超过M,可是暴力复杂度不对。
    于是考虑自下而上合并树(开始每棵树内只有一个节点,就是自己)

    每个树是一个堆,我们维护树的节点个数和薪水总和,合并时,不断弹出堆顶薪水最大的直到薪水总和不超过M,然后用领导力*节点个数更新答案。
    发现这个模型就是裸的左偏树。

    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    using namespace std;
     
    typedef long long LL;
     
    #define N 100010
     
    int l[N],r[N],fa[N];
    int tree[N],siz[N],d[N];
     
    LL ld[N],c[N],sum[N];
     
    int n;
     
    LL m,ans;
     
    int merge(int x,int y)
    {
        if (!x)
            return y;
        if (!y)
            return x;
        if (c[x]<c[y])
            swap(x,y);
        r[x]=merge(r[x],y);
        if (d[r[x]]>d[l[x]])
            swap(l[x],r[x]);
        d[x]=d[r[x]]+1;
        sum[x]=sum[l[x]]+sum[r[x]]+c[x];
        siz[x]=siz[l[x]]+siz[r[x]]+1;
        return x;
    }
     
    int main()
    {
        scanf("%d%lld",&n,&m);
        for (int i=1;i<=n;i++)
        {
            scanf("%d%lld%lld",&fa[i],&c[i],&ld[i]);
            tree[i]=i;
            siz[i]=1;
            sum[i]=c[i];
        }
        for (int i=n;i>=1;i--)
        {
            while (sum[tree[i]]>m)
                tree[i]=merge(l[tree[i]],r[tree[i]]);
            ans=max(ans,siz[tree[i]]*ld[i]);
            if (i!=1)
                tree[fa[i]]=merge(tree[fa[i]],tree[i]);
        }
        printf("%lld",ans);
        return 0;
    }
    
    

      

  • 相关阅读:
    C#开发代码的小技巧1
    17. 装箱、拆箱的最小化
    Google Map开发(一) ASP.NET中调用Google Map API实现简单的地图显示
    C#可空类型
    C#如何扩展类型的内置方法
    Linq合并两个DataTable
    <br style="clear:both" /><br />
    GridView内容<br />换行
    数据库连接字符串大全
    JS将Table导出到Excel
  • 原文地址:https://www.cnblogs.com/yangjiyuan/p/5761022.html
Copyright © 2011-2022 走看看