• 「Luogu1552」[APIO2012]派遣


    「Luogu1552」[APIO2012]派遣

    最近状态都不是很好,写完这个题感觉手感好像恢复了一些


    problem

    Solution

    这个数据范围显然树形DP是做不了的

    我们考虑,在预算范围内,选中的忍者越多越好,那么我们在一棵子树中选中的忍者一定是薪水最少的若干个

    对每个节点维护一个大根堆,并记录每个堆的大小和堆中元素的权值和

    考虑一棵子树时,用类似树形DP的方法将所有儿子合并到根

    如果堆中元素权值和大于预算,不断弹出堆顶直到权值和不大于预算即可

    最后对子树进行统计,更新答案

    可并堆可以用左偏树实现

    另外,还需要记录每个节点对应的左偏树的根的编号

    Code

    一开始没开long long还wa了一发

    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    typedef long long ll;
    
    template <typename T>void read(T &t)
    {
        t=0;int f=0;char c=getchar();
        while(!isdigit(c)){f|=c=='-';c=getchar();}
        while(isdigit(c)){t=t*10+c-'0';c=getchar();}
        if(f)t=-t;
    }
    
    const int maxn=100000+5;
    int n,root;
    ll m;
    ll mng[maxn];
    ll ans;
    
    struct edge
    {
        int u,v,nxt;
    }g[maxn];
    
    int head[maxn],ecnt;
    void eADD(int u,int v)
    {
        g[++ecnt].u=u;
        g[ecnt].v=v;
        g[ecnt].nxt=head[u];
        head[u]=ecnt;
    }
    
    int rec[maxn];
    struct node
    {
        int ls,rs,dist;
        ll val,siz,sum;
    }mxh[maxn];
    
    int Merge(int x,int y)
    {
        if(!x || !y)return x+y;
        if(mxh[x].val<mxh[y].val)swap(x,y);
        mxh[x].rs=Merge(mxh[x].rs,y);
        if(mxh[mxh[x].ls].dist<mxh[mxh[x].rs].dist)
            swap(mxh[x].ls,mxh[x].rs);
        mxh[x].dist=mxh[mxh[x].rs].dist+1;
        mxh[x].siz=mxh[mxh[x].ls].siz+mxh[mxh[x].rs].siz+1;
        mxh[x].sum=mxh[mxh[x].ls].sum+mxh[mxh[x].rs].sum+mxh[x].val;
        return x;
    }
    
    int Pop(int x)
    {
        int ls=mxh[x].ls,rs=mxh[x].rs;
        return Merge(ls,rs);
    }
    
    void dfs(int u)
    {
        for(register int i=head[u];i;i=g[i].nxt)
        {
            int v=g[i].v;
            dfs(v);
            rec[u]=Merge(rec[u],rec[v]);
        }
        while(mxh[rec[u]].sum>m && mxh[rec[u]].siz)
            rec[u]=Pop(rec[u]);
        ans=max(ans,1ll*mxh[rec[u]].siz*mng[u]);
    }
    
    int main()
    {
        read(n),read(m);
        for(register int i=1;i<=n;++i)
        {
            int u;
            read(u),read(mxh[i].val),read(mng[i]);
            mxh[i].sum=mxh[i].val;
            mxh[i].siz=1;
            rec[i]=i;
            if(u)eADD(u,i);
            else root=i;
        }
        dfs(root);
        printf("%lld",ans); 
        return 0;
    }
    
  • 相关阅读:
    outlook express 发不出邮件问题
    当您更改为一个值该值不是有效的启动参数对于群集实例的 SQL Server 2000 或 SQL Server 2005 的 SQL Server 服务不能启动
    (转)为gridview“删除”列添加确认对话框
    关于开心网
    Windows 群集(一)
    你们公司有软件实验室吗?
    数据安全性小结
    请教:如何限制C++.net托管组件在设计时不能运行?
    test:请不要访问
    将WDL(华康)等电子文件转换为PDF后转换其它格式文件的方法
  • 原文地址:https://www.cnblogs.com/lizbaka/p/10657928.html
Copyright © 2020-2023  润新知