2019牛客暑期多校训练营(第七场)- Governing sand
线段树
按照高度排序以后,对价格的值域建线段树,维护数量和总费用。
每次枚举一个高度,假设该高度的树有m棵,比它的高的树显然要全部砍掉,直接用前缀和统计费用,又假设比他低的树有n棵,
我们要砍的数量就是n - m + 1,在值域线段树里查询前n-m+1棵树的总费用即可。
#include <bits/stdc++.h>
#define INF 2333333333333333333
#define full(a, b) memset(a, b, sizeof a)
#define __fastIn ios::sync_with_stdio(false), cin.tie(0)
#define range(x) (x).begin(), (x).end()
#define pb push_back
using namespace std;
typedef long long LL;
inline int lowbit(int x){ return x & (-x); }
inline int read(){
int ret = 0, w = 0; char ch = 0;
while(!isdigit(ch)){
w |= ch == '-', ch = getchar();
}
while(isdigit(ch)){
ret = (ret << 3) + (ret << 1) + (ch ^ 48);
ch = getchar();
}
return w ? -ret : ret;
}
template <typename A>
inline A lcm(A a, A b){ return a / __gcd(a, b) * b; }
template <typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){
A ans = 1;
for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
return ans;
}
const int N = 200005;
int n, cnt;
LL sum[N<<2], pre[N], num[N], tree[N<<2], b[N];
struct Tree{
int h, c, p;
Tree(){}
Tree(int h, int c, int p): h(h), c(c), p(p){}
bool operator < (const Tree &rhs) const {
return h < rhs.h;
}
}t[N];
void init(){
cnt = 0;
full(b, 0), full(pre, 0), full(num, 0);
full(tree, 0), full(sum, 0);
}
void buildTree(int rt, int l, int r){
if(l == r){
tree[rt] = sum[rt] = 0;
return;
}
int mid = (l + r) >> 1;
buildTree(rt << 1, l, mid);
buildTree(rt << 1 | 1, mid + 1, r);
}
void insert(int rt, int l, int r, int val, int k){
tree[rt] += 1LL * k, sum[rt] += 1LL * val * k;
if(l == r) return;
int mid = (l + r) >> 1;
if(val <= mid) insert(rt << 1, l, mid, val, k);
else insert(rt << 1 | 1, mid + 1, r, val, k);
}
LL query(int rt, int l, int r, LL k){
if(l == r) return l * k;
int mid = (l + r) >> 1;
if(k <= tree[rt << 1]) return query(rt << 1, l, mid, k);
return sum[rt << 1] + query(rt << 1 | 1, mid + 1, r, k - tree[rt << 1]);
}
int main(){
while(~scanf("%d", &n)){
init();
for(int i = 1; i <= n; i ++){
scanf("%d%d%d", &t[i].h, &t[i].c, &t[i].p);
}
sort(t + 1, t + n + 1);
int j;
for(int i = 1; i <= n; i = j){
cnt ++, j = i;
pre[cnt] += pre[cnt - 1], num[cnt] += num[cnt - 1];
while(j <= n && t[j].h == t[i].h){
pre[cnt] += 1LL * t[j].c * t[j].p;
num[cnt] += t[j].p;
b[cnt] += t[j].p;
j ++;
}
}
LL ans = INF;
int tot = 0;
for(int i = 1; i <= n; i = j){
tot ++, j = i;
LL cur = pre[cnt] - pre[tot];
LL x = num[tot - 1];
if(x - b[tot] + 1 > 0)
cur += query(1, 1, 200, x - b[tot] + 1);
ans = min(ans, cur);
while(j <= n && t[j].h == t[i].h) insert(1, 1, 200, t[j].c, t[j].p), j ++;
}
printf("%lld\n", ans);
}
return 0;
}