zoukankan      html  css  js  c++  java
  • [洛谷P1552] [APIO2012]派遣(左偏树)

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

    Part 1 理解题目

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

    Part 2 解题思想

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

    Part 3 code

        #include<iostream>  
        #include<cstdlib>  
        #include<cstdio>  
        #include<cmath>  
        #include<cstring>  
        #include<iomanip>  
        #include<algorithm>  
        #include<ctime>  
        #include<queue>  
        #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=(x<<3)+(x<<1)+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<=n;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;  
        } 




    哪怕人间是炼狱,梦想永远是天堂
    继续走下去吧,理想永远都年轻,花儿一定会再次盛开
  • 相关阅读:
    数据结构:树[data struct: tree]
    关于计算机学科的一些期刊和会议(转)
    这个世界究竟是怎么了
    [思考]怎么在C#中加入新功能
    vsta相关
    Practical numerical methods with C#
    C# (CSharp)中的foreach,for关键词
    代码生成相关
    没有可用于当前位置的源代码 解决办法
    access数据库删除两个日期之间 的数据 SQL语句
  • 原文地址:https://www.cnblogs.com/cjoierljl/p/8641019.html
Copyright © 2011-2022 走看看