zoukankan      html  css  js  c++  java
  • 【刷题】【数据结构】【堆】配对堆 [APIO2012] 派遣

    这一题中各位忍者的关系其实是一棵树:

    b[i]是他的上司,也是他的父节点

    一个父节点可能有多个儿子

    父子关系就是命令的传达关系,父亲能传给儿子

    所以如果选中一个管理者,那他就是这棵树的根

    因为忍者只要祖宗是管理者,就可以传话,

    所以管理者可以选择的忍者的范围就是他的所有子孙

    而传话的忍者也可以不被调遣,管理者也可以

    所以选择忍者时,不用要求这个被选择点的父亲也被选择

    那么把所有点放到一个堆中,然后按照w的值重新开始排序,合并

    找最大值删除就好

    //思路:其实这道题很保留,枚举管理者,枚举被派遣的人
    //但是,是有方法的枚举
    #include<cstdio>
    #include<cstdlib>
    #include<vector>
    #include<queue>
    using namespace std;
    int n,m;
    long long ans;
    const int N=100003;
    vector <int > son[N];
    int b[N],w[N],val[N];
    
    int fa[N];
    int find(int x) { return fa[x]==0?x:fa[x]=find(fa[x]); }
    int merge(int a,int b)//这里是w的最大堆 
    {
        if(a==b) return a;
        if(w[a]<=w[b]) return fa[a]=b,son[b].push_back(a), b;
        else return fa[b]=a,son[a].push_back(b), a; 
    }
    int del(int x)
    {
        queue <int> s; 
        int siz=son[x].size() ;
        for(int i=0;i<siz;i++)
        {
            int t=son[x][i];
            fa[t]=0;
            s.push(t);
        }
        while((siz--)>1)
        {
            int a=s.front();s.pop();
            int b=s.front();s.pop();
            s.push(merge(a,b));
        }
        if(!s.empty() ) fa[x]=s.front();
        son[x].clear() ;
        return w[x];
    }
    
    int sz[N];
    long long sum[N];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&b[i],&w[i],&val[i]);
            ans=max((long long)val[i],ans);//1
            sz[i]=1,sum[i]=w[i];
        }
        for(int i=n;i;i--)//每一个忍者的老板的编号一定小于自己的编号Bi<i
        //这连欧拉序都省了, 直接从n(就是底部)开始遍历,往上走 
        {
            int f=b[i];//这就是根
            sz[f]+=sz[i],sum[f]+=sum[i];
            merge(find(i),find(f));//!!!!!!!这里不可以直接写f,
            //因为f有不止一个儿子,在之前已经被拉出来merge过了,find(f)不一定等于f 
            while(sum[f]>m)
            {
                sum[f]-=del(find(f));
                sz[f]--;
            }
            ans=max(ans,sz[f]*1LL*val[f] );
        }
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    @Aspect 注解使用详解
    Mysql的4个隔离级别
    【学习笔记】二分类问题中的“最大似然”与“交叉熵损失”概念的理解
    【转】对“先验概率”与“后验概率”概念的通俗理解
    nginx——安装部署vue项目
    JWT
    Vue——自定义组件实现vmodel
    Vue——子级向父级传递参数
    SpringBoot2(十四)全局异常切面
    Vue——ElementUI表格分页
  • 原文地址:https://www.cnblogs.com/xwww666666/p/11260755.html
Copyright © 2011-2022 走看看