[洛谷P1552] [APIO2012]派遣(左偏树)

2021-04-20 05:28

阅读:504

标签:mil   工资   print   维护   tchar   class   ace   queue   getc   

这道题是我做的左偏树的入门题,奈何还是看了zsy大佬的题解才能过,唉,我太弱了。

Part 1 理解题目

很显然,通过管理关系的不断连边,最后连出来的肯定是一棵树,那么不难得出,当一个忍者作为管理者时,最优解一定是去除掉所有的较大工资的忍者,剩下的忍者符合费用要求时,答案是管理者的管理能力×剩下的忍者数量。并且我们可以推出,当一棵子数中的一棵小子树中去掉了一个忍者,那么那个忍者一定不会对当前的子树有答案贡献。

Part 2 解题思想

都理解了题目了,就很清楚了,我们在dfs过程中记录一下集合元素,并把此节点以下所有的子树全部合并入一个堆里(dfs过程中已经处理了,每个堆都是最优堆),那么开始弹元素,维护大根堆,一个个弹出最大值,直到刚好符合要求,此时答案就是堆中剩余元素的数量×当前节点的管理能力,取max。完啦!

Part 3 code

    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include#define rg register  
    #define lst long long  
    using namespace std;  
    #define ll long long  
    const int N = 100005;  
    struct edge{int to,next;}a[N];  
    int head[N],cnt;  
    int n,Master,ls[N],rs[N],dis[N];  
    ll m,C[N],L[N],sum[N],sz[N],ans;  
    ll gi()  
    {  
        ll x=0,w=1;char ch=getchar();  
        while ((ch‘0||ch>9)&&ch!=-) ch=getchar();  
        if (ch==-) w=0,ch=getchar();  
        while (ch>=0&&ch‘9) x=(x3)+(x1)+ch-0,ch=getchar();  
        return w?x:-x;  
    }  
    void Link(int u,int v)  
    {  
        a[++cnt]=(edge){v,head[u]};  
        head[u]=cnt;  
    }  
    int Merge(int A,int B)  
    {  
        if (!A||!B) return A+B;  
        if (C[A]C[B]) swap(A,B);  
        rs[A]=Merge(rs[A],B);  
        if (dis[ls[A]]dis[rs[A]]) swap(ls[A],rs[A]);  
        dis[A]=dis[rs[A]]+1;  
        return A;  
    }  
    int Delete(int A)  
    {  
        return Merge(ls[A],rs[A]);  
    }  
    int dfs(int u)  
    {  
        int A=u,B;  
        sum[u]=C[u];sz[u]=1;  
        for (int e=head[u];e;e=a[e].next)  
        {  
            int v=a[e].to;  
            B=dfs(v);  
            A=Merge(A,B);  
            sum[u]+=sum[v];sz[u]+=sz[v];  
        }  
        while (sum[u]>m)  
        {  
            sum[u]-=C[A];sz[u]--;  
            A=Delete(A);  
        }  
        ans=max(ans,L[u]*sz[u]);  
        return A;  
    }  
    int main()  
    {  
        n=gi();m=gi();  
        for (int i=1;i)  
        {  
            int u=gi();  
            if (!u) Master=i;  
            else Link(u,i);  
            C[i]=gi();L[i]=gi();  
        }  
        dfs(Master);  
        printf("%lld",ans);  
        return 0;  
    } 

 

[洛谷P1552] [APIO2012]派遣(左偏树)

标签:mil   工资   print   维护   tchar   class   ace   queue   getc   

原文地址:https://www.cnblogs.com/cjoierljl/p/8641019.html


评论


亲,登录后才可以留言!