题意:n种树,每种树有p数量,c砍树话费,h高度,如果最高的树的数量大于总树数量的一半则合法
题解:题目中有一个没提到的点,会有相同高度的树,这种情况下得把这些树的高度加起来,作为同一种树(但实际上这些树的数量和花费是不一样的,慎重!!!因为我被卡了好久)
首先我们枚举最高树的高度作为对应的,即排一下序从低往高取,1.比他高度高的都删掉,这里可以用前缀和处理2.比他低的要删掉k个使其合法,问题来了,这k个怎么删呢,两种办法,第一种是维护前k大的和的线段树,第二种是计数排序(因为c的范围只有两百),我采用了计数排序,每次使用完更新一下计数数组就可以了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mem(s) memset(s, 0, sizeof(s))
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const int maxn = 1e5+5;
const int mod = 998244353;
struct node {
ll h,p;
ll c;
bool operator <(const node & rhs)const{
return h<rhs.h;
}
}a[maxn];
ll co[maxn],sum[maxn];
int main()
{
int n;
while(scanf("%d",&n)!=EOF){
memset(co,0,sizeof(co));
memset(sum,0,sizeof(sum));
ll ans=1e18;
for(int i=1;i<=n;i++)
scanf("%lld%lld%lld",&a[i].h,&a[i].c,&a[i].p);
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+a[i].c*a[i].p;
}
ll coun=0;
for(int i=1;i<=n;i++){
ll c,cur=i,tmp=0;
for(int j=i;j<=n&&a[i].h==a[j].h;j++){
tmp+=a[j].p;
cur=j;
}
c=sum[n]-sum[cur];
if(tmp*2>coun+tmp){
//cout<<"!"<<endl;
ans=min(c,ans);
}else {
ll k=coun-tmp+1;
for(int j=1;j<=200;j++){
if(co[j]>=k){
c+=k*j;
break;
}else {
k-=co[j];
c+=co[j]*j;
}
}
ans=min(c,ans);
}
for(int j=i;j<=cur;j++){
//tmp+=a[j].p;
co[a[j].c]+=a[j].p;
coun+=a[j].p;
}
i=cur;
}
printf("%lld\n",ans);
}
return 0;
}