题目链接:
https://ac.nowcoder.com/acm/contest/887/C
题意:
N
N
N颗树,第i种树有
P
[
i
]
P[i]
P[i]颗,高度为
H
[
i
]
H[i]
H[i],砍掉这种树代价为
C
[
i
]
C[i]
C[i]
求最小的花费,使得最高的树的数量超过剩下树总数的一半
题解:
按高度从高到低进行排序,然后用权值线段树维护。
每个高度都查询砍完需要的树的最小花费,更新答案
每次查询完当前高度,砍完当前高度的树(更新权值线段树)
代码:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define sz sizeof
#define lc u<<1
#define rc u<<1|1
#define m (l+r)/2
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> Pair;
const int MAX = 1e5 + 10;
struct SegTree {
int l, r;
ll n, s;
}t[500 << 2];
void build(int u, int l, int r) {
t[u].l = l, t[u].r = r, t[u].n = t[u].s = 0;
if (l == r)return;
build(lc, l, m); build(rc, m + 1, r);
}
void pushup(int u) {
t[u].n = t[lc].n + t[rc].n;
t[u].s = t[lc].s + t[rc].s;
}
void update(int u, ll c, ll n) {
int l = t[u].l, r = t[u].r;
if (l == r) {
t[u].n += n;
t[u].s += n * c;
return;
}
if (c <= m)update(lc, c, n);
else if (c > m)update(rc, c, n);
pushup(u);
}
ll query(int u, ll last) {
int l = t[u].l, r = t[u].r;
if (last <= 0)return 0;
if (l == r)return 1ll * last * l;
if (t[lc].n >= last)return query(lc, last);
else return t[lc].s + query(rc, last - t[lc].n);
}
struct node {
ll h, c, n;
bool operator < (const node& a)const {
return h > a.h;
}
}a[MAX];
int n;
int main() {
#ifdef ACM_LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
while (~scanf("%d", &n)) {
build(1, 1, 200);
ll tot = 0;
for (int i = 1; i <= n; i++) {
scanf("%lld%lld%lld", &a[i].h, &a[i].c, &a[i].n);
update(1, a[i].c, a[i].n);
tot += a[i].n;
}
sort(a + 1, a + 1 + n);
ll minn = 1e18, pre_n = 0, pre_s = 0, now_n, now_s;
for (int i = 1; i <= n; i++) {
now_n = now_s = 0;
while (i < n && a[i].h == a[i + 1].h) {
update(1, a[i].c, -a[i].n);
now_n += a[i].n;
now_s += a[i].n * a[i].c;
i++;
}
update(1, a[i].c, -a[i].n);
now_n += a[i].n;
now_s += a[i].n * a[i].c;
minn = min(minn, query(1, tot - pre_n - 2 * now_n + 1) + pre_s);
pre_s += now_s;
pre_n += now_n;
}
printf("%lld\n", minn);
}
return 0;
}