当前位置 博文首页 > ttoobne:2019牛客暑期多校训练营(第九场)H Cutting Bamboos(

    ttoobne:2019牛客暑期多校训练营(第九场)H Cutting Bamboos(

    作者:[db:作者] 时间:2021-08-30 10:33

    题目链接

    题解:

    我们可以二分砍到的高度,那么怎么求 L 到 R 区间内一个高度能砍掉的竹子呢?那么可以用一颗可持久化线段树来使区间的高度变得有序。

    具体的,用主席树维护区间的高度之和与区间每个高度出现的次数。每次可以计算出高于二分高度的和 sum 与出现次数 num,那么剪掉的部分就是 sum - 二分的高度 * num 。那么就直接二分了。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    #define int ll
    #define PI acos(-1.0)
    #define INF 0x3f3f3f3f3f3f3f3f
    #define P pair<int, int>
    #define fastio ios::sync_with_stdio(false), cin.tie(0)
    const int mod = 998244353;
    const int M = 1000000 + 10;
    const int N = 200000 + 10;
    
    int pres[N];
    struct node {
        int ls, rs;
        int sum, num;
    } tree[N<<5];
    int rt[N], cnt;
    
    void build(int &now, int l = 1, int r = 100000)
    {
        now = ++cnt;
        tree[now].num = tree[now].sum = 0;
        if(l == r) return ;
        int mid = (l + r) >> 1;
        build(tree[now].ls, l, mid);
        build(tree[now].rs, mid + 1, r);
    }
    
    void add(int &now, int pre, int val, int l = 1, int r = 100000)
    {
        now = ++cnt;
        tree[now] = tree[pre];
        if(l == r) {
            tree[now].num ++;
            tree[now].sum += val;
            return ;
        }
        int mid = (l + r) >> 1;
        if(val <= mid) add(tree[now].ls, tree[pre].ls, val, l, mid);
        else add(tree[now].rs, tree[pre].rs, val, mid + 1, r);
    
        tree[now].num = tree[tree[now].ls].num + tree[tree[now].rs].num;
        tree[now].sum = tree[tree[now].ls].sum + tree[tree[now].rs].sum;
    }
    
    int query_num(int p, int q, int L, int R = 100000, int l = 1, int r = 100000)
    {
        if(L <= l && r <= R) return tree[q].num - tree[p].num;
        int mid = (l + r) >> 1, ans = 0;
        if(L <= mid) ans += query_num(tree[p].ls, tree[q].ls, L, R, l, mid);
        if(mid < R) ans += query_num(tree[p].rs, tree[q].rs, L, R, mid + 1, r);
        return ans;
    }
    
    int query_sum(int p, int q, int L, int R = 100000, int l = 1, int r = 100000)
    {
        if(L <= l && r <= R) return tree[q].sum - tree[p].sum;
        int mid = (l + r) >> 1, ans = 0;
        if(L <= mid) ans += query_sum(tree[p].ls, tree[q].ls, L, R, l, mid);
        if(mid < R) ans += query_sum(tree[p].rs, tree[q].rs, L, R, mid + 1, r);
        return ans;
    }
    
    signed main()
    {
        int n, q;
        scanf("%lld %lld", &n, &q);
        build(rt[0]);
        for(int i = 1, h; i <= n; i ++) {
            scanf("%lld", &h);
            pres[i] = pres[i - 1] + h;
            add(rt[i], rt[i - 1], h);
        }
        for(int i = 1, l, r, x, y; i <= q; i ++) {
            scanf("%lld %lld %lld %lld", &l, &r, &x, &y);
            double ql = 0, qr = 100010;
            while(ql + 1e-7 < qr) {
                double mid = (ql + qr) / 2;
                int qmid = ceil(mid);
                int qsum = query_sum(rt[l - 1], rt[r], qmid);
                int qnum = query_num(rt[l - 1], rt[r], qmid);
                if(qsum - qnum * mid >= 1.0 * (pres[r] - pres[l - 1]) * x / y) ql = mid;
                else qr = mid;
            }
            printf("%.10lf\n", qr);
        }
    }
    
    /*
    
      Rejoicing in hope, patient in tribulation.
    
    */
    

    ?

    cs