2019牛客多校第7场 C: Governing sand

题意:

题意大概就是要求是一种高度的树超过一半所需要的花费是多少

思路:

我的思路是做一个前缀和,然后每次枚举一个高度,计算出对应的值
求砍掉比他高的树的时候,就是做一个前缀和,如果是要求砍掉比他小的树的最小价值
那么我们可以按照权值做一颗线段树,那么查询前k小的和即可
然后将两个权值加起来保存最小的值

附上代码:

#include <bits/stdc++.h>
using namespace std;
/*
segtree[1].num - arr[i].p
本题存在坑点,不同种类的树有相同的高度
将不同种类的树 放到相同高度的vector里面
枚举高度
存在一个前缀和
*/
typedef long long LL;
int n;
const int MAXN = 1e5 + 5;
struct Tree{
    LL h, c, p;
    friend bool operator< (const Tree &a, const Tree &b){
        return a.h < b.h;
    }
}arr[MAXN];
LL sum[MAXN];
vector<LL>vec, h_arr;
vector<int>vec_tree[MAXN];
struct Segtree{
    struct NODE{
        int l, r;
        LL sum, num;
    }tree[MAXN << 2];
    void Init(){
        for(int i = 0; i <= 4 * n; i ++){
            tree[i].l = tree[i].r = tree[i].sum = tree[i].num = 0;
        }
    }
    inline void push_up(int root){
        tree[root].sum = tree[root << 1].sum + tree[root << 1 | 1].sum;
        tree[root].num = tree[root << 1].num + tree[root << 1 | 1].num;
        return ;
    }
    void build(int root, int l, int r){
        tree[root].l = l, tree[root].r = r;
        if(l == r){
            tree[root].sum = tree[root].num = 0;
            return ;
        }
        int mid = (l + r) >> 1;
        build(root << 1, l, mid);
        build(root << 1 | 1, mid + 1, r);
        return ;
    }
    void update(int root, int cnt, LL val){
        if(tree[root].l == cnt && tree[root].r == cnt){
            tree[root].sum += val * vec[cnt - 1];
            tree[root].num += val;
            return ;
        }
        int mid = (tree[root].l + tree[root].r) >> 1;
        if(cnt <= mid){
            update(root << 1, cnt, val);
        }
        else{
            update(root << 1 | 1, cnt, val);
        }
        push_up(root);
    }
    LL query(int root, LL cnt){
        if(tree[root].num == cnt){
            return tree[root].sum;
        }
        if(tree[root].l == tree[root].r){
            return vec[tree[root].l - 1] * cnt;
        }
        if(cnt > tree[root << 1].num){
            return query(root << 1, tree[root << 1].num) + query(root << 1 | 1, cnt - tree[root << 1].num);
        }
        else{
            return query(root << 1, cnt);
        }
    }
}seg;
int Get(LL x){
    return lower_bound(vec.begin(), vec.end(), x) - vec.begin() + 1;
}
int Geth(LL x){
    return lower_bound(h_arr.begin(), h_arr.end(), x) - h_arr.begin() + 1;
}
int main(){
    while(~scanf("%d", &n)){
        memset(sum, 0, (n + 3) * sizeof(sum[0]));
        vec.clear(), h_arr.clear();
        for(int i = 0; i <= n; i ++){
            vec_tree[i].clear();
        }
        seg.Init();
        for(int i = 0; i < n; i ++){
            scanf("%lld%lld%lld", &arr[i].h, &arr[i].c, &arr[i].p);
            vec.push_back(arr[i].c), h_arr.push_back(arr[i].h);
        }
        sort(arr, arr + n);
        sort(vec.begin(), vec.end());
        vec.erase(unique(vec.begin(), vec.end()), vec.end());
        sort(h_arr.begin(), h_arr.end());
        h_arr.erase(unique(h_arr.begin(), h_arr.end()), h_arr.end());
        sum[0] = arr[0].p * arr[0].c;
        for(int i = 1; i < n; i ++){
            sum[i] = sum[i - 1] + arr[i].p * arr[i].c;
        }
        seg.build(1, 1, n);
        for(int i = 0; i < n; i ++){
            vec_tree[Geth(arr[i].h)].push_back(i);
        }
        LL ans = __LONG_LONG_MAX__;
        for(int i = 1; i <= h_arr.size(); i ++){
            LL sums = 0;
            for(int j = 0; j < vec_tree[i].size(); j ++){
                sums += arr[vec_tree[i][j]].p;
            }
            if(sums > seg.tree[1].num){
                ans = min(ans, sum[n - 1] - sum[vec_tree[i][vec_tree[i].size() - 1]]);
            }
            else{
                ans = min(ans, sum[n - 1] - sum[vec_tree[i][vec_tree[i].size() - 1]] + seg.query(1, seg.tree[1].num - sums + 1));
            }
            for(int j = 0; j < vec_tree[i].size(); j ++){
                seg.update(1, Get(arr[vec_tree[i][j]].c), arr[vec_tree[i][j]].p);
            }
        }
        printf("%lld\n", ans);
    } 
    return 0;
}
posted @ 2019-08-16 22:07  moxin0509  阅读(173)  评论(0编辑  收藏  举报