C题:
链接:https://ac.nowcoder.com/acm/contest/887/C
题意: n中树,第i种树有P[i]颗,砍掉每颗树的代价是C[i], 高度是H[i]. 需要用最小的代价砍掉一些树,让最高的树超过一半。
分析:从从低到高枚举最高的树,在剩下的树当中砍掉代价最小的。可以用一颗线段树维护。线段树按照代价从小到大的顺序构建,支持单点插入,查询前x个的总和。
Ac code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
struct Tree{
ll num,sum;
}tree[maxn<<2];
struct Node{
int h,c,p,id;
}node[maxn];
void pushup(int rt)
{
tree[rt].num=tree[rt<<1].num+tree[rt<<1|1].num;
tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
}
void buildtree(int rt,int l,int r)
{
if(l==r){
tree[rt].sum=tree[rt].num=0;
return;
}
int mid=(l+r)>>1;
buildtree(rt<<1,l,mid);
buildtree(rt<<1|1,mid+1,r);
pushup(rt);
}
ll query(int rt,int l,int r,ll num)///求前num棵树的花费最小总和
{
if(num<=0) return 0;
if(num>=tree[rt].num) return tree[rt].sum;
if(l==r) return tree[rt].sum/tree[rt].num*num;
int mid=(l+r)>>1;
return query(rt<<1,l,mid,num)+query(rt<<1|1,mid+1,r,num-tree[rt<<1].num);
}
void update(int rt,int l,int r,int idx,int c,int p)
{
if(l==r){
tree[rt].num+=p;
tree[rt].sum+=1ll*c*p;
return;
}
int mid=(l+r)>>1;
if(idx<=mid) update(rt<<1,l,mid,idx,c,p);
else update(rt<<1|1,mid+1,r,idx,c,p);
pushup(rt);
}
bool cmp1(Node &a,Node &b)
{
return a.c<b.c;
}
bool cmp2(Node &a,Node &b)
{
return a.h<b.h;
}
int main()
{
int n;
while(~scanf("%d",&n)){
ll ans=0;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&node[i].h,&node[i].c,&node[i].p);
ans+=1ll*node[i].c*node[i].p;
}
sort(node+1,node+n+1,cmp1);
for(int i=1;i<=n;i++)
node[i].id=i;
buildtree(1,1,n);
sort(node+1,node+n+1,cmp2);
ll res=ans-1ll*node[1].c*node[1].p;///高于当前最高的树的花费总和
ll tot=0;///当前加入线段树的树数量总和
ll maxnum=node[1].p;///当前最高的树的数量总和
int j=1;
for(int i=2;i<=n+1;i++)
{
if(i==n+1||node[i].h!=node[i-1].h){///每次以i-1为当前最高的树
ll tmp=query(1,1,n,tot-maxnum+1)+res;///低于当前最高树的前maxnum-1可以留下,所以前tot-(maxnum-1)棵花费最小的树必须砍掉
ans=min(ans,tmp);
maxnum=node[i].p;///每次更新给下次用
if(i<n+1){///i=n+1时更新已经没有意义了
while(j<i){
update(1,1,n,node[j].id,node[j].c,node[j].p);///按花费从小到大插入线段树
tot+=node[j].p;
j++;
}
}
}
else maxnum+=node[i].p;
if(i<n+1) res-=1ll*node[i].c*node[i].p;
}
printf("%lld\n",ans);
}
return 0;
}