zoukankan      html  css  js  c++  java
  • Governing sand(主席树/贪心)(2019牛客暑期多校训练营(第七场))

    示例:
    输入:
    2
    5 1 1
    1 10 1
    2
    5 1 2
    3 2 3
    输出:
    1
    2

    题意:n种树,第i种树有P[i]颗,砍掉每颗树的代价是C[i], 高度是H[i]。需要用最小的花费砍掉一些树,让最高的树超过一半。

    题解:按高度分类,从小到大枚举最大高度,比当前枚举的高度 h 要高的,一定删,比它小的,如果删前 ? 小的。

    贪心代码:

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 const int maxx=1e5+20;
     5 struct node{
     6     ll h,v,p;
     7     bool operator<(const node&a)const{
     8         return h<a.h;
     9     }
    10 }tree[maxx];
    11 ll B[220],arr[maxx],pre[maxx];//B储存已经遍历过的树在该价值的数量,arr储存第i高及比第i高的树都被砍掉的花费,pre储存第i高树矮的树的数量
    12 int main()
    13 {
    14     ll n;
    15     while(~scanf("%lld",&n)){
    16         memset(B,0,sizeof(B));
    17         for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&tree[i].h,&tree[i].v,&tree[i].p);
    18         sort(tree+1,tree+1+n);//从低到高排序高度
    19         arr[n+1]=0;
    20         for(int i=n;i>=1;i--)arr[i]=arr[i+1]+tree[i].v*tree[i].p;
    21         pre[0]=0;
    22         for(int i=1;i<=n;i++)pre[i]=pre[i-1]+tree[i].p;
    23         ll ans=1e18;
    24         for(int i=1,j=1;i<=n;i=j){//从小到大枚举最大高度
    25             while(j<=n&&tree[j].h==tree[i].h)j++;
    26             ll sums=0;
    27             for(int k=i;k<j;k++)sums+=tree[k].p;
    28             ll cost=arr[j];
    29             if(sums<=pre[i-1]){//如果第i高的树的数量小于比它矮的树的数量,即将价值数组进行从小到大处理
    30                 ll need=pre[i-1]-sums+1;
    31                 for(int t=1;t<=200;t++){
    32                     if(B[t]<=need){
    33                         cost+=B[t]*t;
    34                         need-=B[t];
    35                     }else{
    36                         cost+=need*t;
    37                         break;
    38                     }
    39                 }
    40             }
    41             ans=min(ans,cost);
    42             for(int k=i;k<j;k++)B[tree[k].v]+=tree[k].p;
    43         }
    44         printf("%lld
    ",ans);
    45     }
    46     return 0;
    47 }

    主席树代码:

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int maxx=2e5+100;
    int tot;
    struct Node{
        LL h,v,p;
        bool operator <(const Node &a)const
        {
            return a.h>h;
        }
    }tree[maxx];
    struct node{
        LL l,r,sum,num;
    }p[maxx*40];
    LL v[maxx],root[maxx];
    LL update(LL rot,LL l,LL r,LL pos,LL num)//建立主席树
    {
        LL book=++tot;
        p[book]=p[rot];//传递上一颗主席树的性质进行修改
        p[book].num+=(LL)num;
        p[book].sum+=(LL)pos*(LL)num;
        if(l==r) return book;
        LL mid=l+r>>1;
        if(pos<=mid) p[book].l=update(p[rot].l,l,mid,pos,num);
        else p[book].r=update(p[rot].r,mid+1,r,pos,num);
        return book;
    }
    LL query(LL rot,LL l,LL r,LL num)//查询
    {
        if(l==r) return (LL)l*(LL)num;
        LL ans=p[p[rot].l].num;
        LL mid=l+r>>1;
        if(num<=ans) return query(p[rot].l,l,mid,num);
        else
        {
            return p[p[rot].l].sum+query(p[rot].r,mid+1,r,num-ans);
        }
    }
    int main()
    {
        int n;
        while(~scanf("%lld",&n)){
            tot=0;
            memset(v,0,sizeof(v));
            for(int i=1;i<=n;i++){
                scanf("%lld%lld%lld",&tree[i].h,&tree[i].v,&tree[i].p);
            }
            sort(tree+1,tree+n+1);
            for(int i=1;i<=n;i++)
                v[i]=v[i-1]+tree[i].p;
            for(int i=1;i<=n;i++){
                root[i]=update(root[i-1],1,210,tree[i].v,tree[i].p);//主席树记录每种树的根节点
            }
            LL Minn=1e18,moneys=0;
            for(int i=n;i>=1;i--){
                LL treenum=0,sums=0;
                while(tree[i].h==tree[i-1].h){
                    treenum+=tree[i].v*tree[i].p;
                    sums+=tree[i].p;
                    i--;
                }
                treenum+=tree[i].v*tree[i].p;
                sums+=tree[i].p;
                LL Smoney=0;
                if(v[i-1]>=sums)Smoney=moneys+query(root[i-1],1,210,v[i-1]-sums+1);//如果第i高的树的数量小于比它矮的树的数量,查询前i-1种树中的需要砍的树的花费
                else Smoney=moneys;
                Minn=min(Minn,Smoney);
                moneys+=treenum;//记录比第i种树高的树的砍掉的花费
            }
            printf("%lld
    ",Minn);
        }
        return 0;
    }
  • 相关阅读:
    浅谈MVVM模式和MVP模式——Vue.js向
    浅谈JavaScript中的null和undefined
    js的单线程和异步
    字符串替换replace方法
    数组的长度、数组元素的添加和删除
    去掉数组中的空元素
    创建数组方法、数组元素的读和写
    Android中H5和Native交互的两种方式
    请求抓取工具
    css层叠规则(层叠样式表)
  • 原文地址:https://www.cnblogs.com/Aamir-Dan/p/11346330.html
Copyright © 2011-2022 走看看