2019牛客第7场——C(Governing sand)

Governing sand

传送门:https://ac.nowcoder.com/acm/contest/887/C
来源:牛客网

题意:给了n种树,每种树的个数是p[i],高度是h[i],砍掉每个树花费是c[i]。要求最高的树要严格比总数目的一半多,问砍掉一些树使得条件满足的最小代价。
 
思路:这个题首先看到数据范围想到要枚举每一种树作为最高的树,这样必然要先把比它高的全都砍掉,排完序后这个可以通过一个后缀和解决,
然后就是砍掉一些比他小的树,使条件满足。
因为后缀和已经处理出砍掉了多少树,而且所有树的总数已知,那么砍掉多少棵树就很显然
K=sum-2*x+1
最后处理砍掉的树的代价最小,直接根据每棵树代价大小把它插入到应该在的位置,这样树状数组上的点的代价就是一个单调的,二分求砍到第几种树即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
const ll inf=0x3f3f3f3f3f3f3f;
struct node
{
    ll w;
    int pos,h,p;
}a[N];
map<int,ll>m;
map<int,int>zz;
int n,b[N];
ll sum[N],num[N],cnt[N],C,W[N];
ll ask_w(int x)
{
    ll ans=0;
    for(;x;x-=x&(-x)) ans+=sum[x];
    return ans;
}
ll ask_num(int x)
{
    ll ans=0;
    for(;x;x-=x&(-x)) ans+=num[x];
    return ans;
}
void add_w(int x,ll y)
{
    for(;x<=n;x+=x&(-x)) sum[x]+=y;
}
void add_num(int x,ll y)
{
    for(;x<=n;x+=x&(-x)) num[x]+=y;
}
bool cmp(node x,node y)
{
    return x.w<y.w;
}
bool cmp2(node x,node y)
{
    return x.h<y.h;
}
int main()
{
    while(~scanf("%d",&n))
    {
        memset(num,0,sizeof num);
        memset(sum,0,sizeof sum);
        memset(W,0,sizeof W);
        memset(cnt,0,sizeof cnt);
        m.clear();
        C=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%lld%lld",&a[i].h,&a[i].w,&a[i].p);
            a[i].pos=i;
        }
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++) b[a[i].pos]=i;
        sort(a+1,a+1+n,cmp2);
        for(int i=1;i<=n;i++)
        {
            zz[b[a[i].pos]]=i;
        }
        ll ans=inf;
        ll las=0;
        for(int i=n;i>=1;i--)
        {
            m[a[i].h]+=a[i].p;
            if(i!=n&&a[i].h==a[i+1].h)
            {
                cnt[i]=cnt[i+1];
                W[i]=W[i+1];
                las+=a[i].p*a[i].w;
            }
            else
            {
                cnt[i]=cnt[i+1]+m[a[i+1].h];
                W[i]=W[i+1]+las;
                las=a[i].p*a[i].w;
            }
            C+=a[i].p;
        }
        for(int i=1;i<=n;i++)
        {
            int l=0,r=n;
            ll tmp=W[i],k=max(0ll,C-cnt[i]-2*m[a[i].h]+1);
            if(a[i].h==a[i-1].h)
            {
                add_w(b[a[i].pos],a[i].w*a[i].p);
                add_num(b[a[i].pos],a[i].p);
                continue;
            }
            while(l<r)
            {
                int mid=(l+r)/2;
                if(ask_num(mid)>=k)
                {
                    r=mid;
                }
                else l=mid+1;
            }
            tmp+=ask_w(max(0,l-1));
            k-=ask_num(max(0,l-1));
            tmp+=k*a[zz[l]].w;
            ans=min(ans,tmp);
            add_w(b[a[i].pos],a[i].w*a[i].p);
            add_num(b[a[i].pos],a[i].p);
        }
        printf("%lld
",ans);
    }
    return 0;
}
 
原文地址:https://www.cnblogs.com/Suiyue-Li/p/11323522.html