题意:
• n种树,第i种树有P[i]颗,砍掉每颗树的代价是C[i], 高度是H[i].
• 需要用最小的代码砍掉一些树,让剩下的最高的树的数量超过一半。
思路:
从从低到高枚举最高的树,在剩下的树当中,用一颗线段树维护, 线段树按照代价从小到大的顺序构建,支持加入类树,查询前x个的总和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
struct node{
ll H,C,P;
}tr[N];
struct Tree{
int l, r;
ll cnt, sum;
}e[205 * 25];
bool cmpH(node a,node b){
return a.H<b.H;
}
ll last[N], cn[205], sss[N], las[N];
inline void pushup(int cur) {
e[cur].cnt = e[cur << 1].cnt + e[cur << 1 | 1].cnt;
e[cur].sum = e[cur << 1].sum + e[cur << 1 | 1].sum;
}
inline void build(int l, int r, int cur) {
e[cur].l = l;
e[cur].r = r;
e[cur].cnt = 0;
e[cur].sum = 0;
if(l == r) {
e[cur].cnt = cn[l];
e[cur].sum = cn[l] * l;
return ;
}
int mid = l + r >> 1;
build(l, mid, cur << 1);
build(mid + 1, r, cur << 1 | 1);
pushup(cur);
}
inline void update(int val, int cur, ll cnt) {
if(e[cur].l == e[cur].r) {
e[cur].cnt -= cnt;
e[cur].sum -= cnt * val;
return ;
}
int mid = e[cur].l + e[cur].r >> 1;
if(val <= mid) update(val, cur << 1, cnt);
else update(val, cur << 1 | 1, cnt);
pushup(cur);
}
inline ll query(int cur, ll cnt) {
if(cnt == 0) return 0;
if(e[cur].cnt == cnt) return e[cur].sum;
if(e[cur].l == e[cur].r) return cnt * e[cur].l;
if(e[cur << 1].cnt >= cnt) return query(cur << 1, cnt);
return e[cur << 1].sum + query(cur << 1 | 1, cnt - e[cur << 1].cnt);
}
int main(){
int n;
while(~scanf("%d",&n)) {
for(int i = 1; i <= 200; i++) cn[i] = 0;
for(int i = 1; i <= n; i++){
scanf("%lld %lld %lld", &tr[i].H, &tr[i].C, &tr[i].P);
cn[tr[i].C] += tr[i].P;
}
sort(tr + 1, tr + 1 + n, cmpH);
int idh = 0;
int lh = 0;
for(int i = 1; i <= n; i++){
if(tr[i].H > lh){
lh = tr[i].H;
tr[i].H = ++idh;
}
else{
tr[i].H = idh;
}
}
build(1,200,1);
las[0] = 0;
for(int i = 0; i <= idh + 1; i++) last[i] = 0, sss[i] = 0;
for(int i = 1; i <= n; i++) last[tr[i].H] += tr[i].P;
for(int i = 1; i <= idh; i++) las[i] = las[i - 1] + last[i];
for(int i = 1; i <= n; i++) sss[tr[i].H] += tr[i].C * tr[i].P;
for(int i = 1; i <= idh; i++) sss[i] = sss[i - 1] + sss[i];
ll ans = 1e16;
int pos = n;
ll sum = 0;
for(int i = idh; i >= 1; i--){
sum = 0;
while(pos && tr[pos].H == i) {
update(tr[pos].C, 1, tr[pos].P);
pos--;
}
sum+=sss[idh] - sss[i];
sum+=query(1, max(0ll, las[i - 1] - (last[i] - 1)) );
ans = min(ans, sum);
}
printf("%lld\n", ans);
}
return 0;
}