2019牛客暑期多校训练营(第九场)H、Cutting Bamboos 主席树+二分

链接:https://ac.nowcoder.com/acm/contest/889/H
来源:牛客网
 

时间限制:C/C++ 5秒,其他语言10秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld

题目描述

There are n bamboos arranged in a line. The i-th bamboo from the left has height hih_{i}hi​.

You are given q queries of the type (l, r, x, y). For each query (l, r, x, y) we consider only the l-th to r-th bamboo inclusive. We want to make y horizontal cuts through these bamboos, such that after each cut, the total length of bamboo cut is the same, and after all y cuts there is no bamboo left. For example, if there are 3 bamboos of height 3, 4, 5 respectively and y = 4. The first cut should be at height 3, after which the heights of the bamboos are 3, 3, 3 respectively and the total amount of bamboo cut is 0 + 1 + 2 = 3. Then, the next 3 cuts should be at height 2, 1, 0 respectively. You want to find out what is the height the x-th cut is performed.

Note that after each query, the bamboos are not actually cut, so the heights of the bamboos remain constant after each query.

 

输入描述:

The first line of input contains two space-separated integers n, q (1 <= n <= 200000, 1 <= q <= 100000).

The next line of input contains n space-separated integers, the i-th of which denotes hi, the height of the i-th bamboo (1 <= hi <= 100000).

The next q lines of input contains 4 space-separated integers each, denoting l, r, x, y (1 <= l <= r <= n, 1 <= x <= y <= 109).

输出描述:

Output q lines of real numbers, the i-th line contains the answer to the i-th query. Your answer will be accepted if its absolute or relative error is less than 10-6.

示例1

输入

复制

5 4
3 5 1 7 4
2 4 3 5
1 4 4 9
1 3 1999 101111
2 2 1 1

输出

复制

2.100000005215406
2.629629638046026
4.822066854685545
0.000000026077032

说明

For the first query, we only consider the bamboos of height 5, 1, 7.

The first cut should be at height 4.7, the total amount of bamboo obtained is 0.3 + 0 + 2.3 = 2.6.

The second cut should be at height 3.4, the total amount of bamboo obtained is 1.3 + 0 + 1.3 = 2.6.

The third cut should be at height 2.1, the total amount of bamboo obtained is 1.3 + 0 + 1.3 = 2.6.

The fourth cut should be at height 13/15, the total amount of bamboo obtained is 37/30 + 2/15 + 37/30 = 2.6.

The fifth cut should be at height 0, the total amount of bamboo obtained is 13/15 + 13/15 + 13/15 = 2.6.

Note that the output values are not exact, but are within the precision requirements.

题解:主席树处理下序列,二分下最高的整数ans,满足区间内 ans及以上高度的和大于等于第x次切除的,然后把ans+1上面的减去后,剩下的就是在这个高度为1的区间内平分了,主席树保存的是高度和 和 高度的数量,方便查询 x 高度以上的高度总和是多少,比较坑的是,求前x次切去的高度时,要先乘x再除y。。。。减小误差

#include 
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
struct node {
    int l, r;
    ll sum, num;
}tree[N * 22];
int n, q;
int h[N];
int root[N], tot;
ll sum[N];
int update(int pre, int l, int r, int pos) {
    int cur = ++tot;
    tree[cur].l = tree[pre].l;
    tree[cur].r = tree[pre].r;
    tree[cur].sum = tree[pre].sum;
    tree[cur].num = tree[pre].num;
    tree[cur].sum += pos;
    tree[cur].num++;
    if(l == r) return cur;
    int mid = (r + l) >> 1;
    if(pos <= mid) tree[cur].l = update(tree[pre].l, l, mid, pos);
    else tree[cur].r = update(tree[pre].r, mid + 1, r, pos);
    return cur;
}
ll cntsum, cntnum;
void query(int pl, int pr, int l, int r, int pos) {
    if(pos <= l) {
//      cout << l << " " << r << " " << tree[pr].sum << " "<< tree[pr].num << " "<> 1;
    if(pos <= mid) query(tree[pl].l, tree[pr].l, l, mid, pos);
    query(tree[pl].r, tree[pr].r, mid + 1, r, pos);
}
int main() {
    int l, r, x, y;
    int ll, rr, mid, ans;
    double cnt, ans_;
    scanf("%d %d", &n, &q);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &h[i]);
        sum[i] = sum[i - 1] + h[i];
        root[i] = update(root[i - 1], 1, 100000, h[i]);
    }
    double tmp;
    while(q--) {
        scanf("%d %d %d %d", &l, &r, &x, &y);
        cnt = 1.0 * (sum[r] - sum[l - 1])  * x / y;
          
        ll = 1, rr = 100000;
        while(ll <= rr) {
            mid = (rr + ll ) >> 1;
            cntsum = 0;
            cntnum = 0;
            query(root[l - 1], root[r], 1, 100000, mid);
            if(cntsum - cntnum * (mid - 1) >= cnt) {
                ans = mid;
                ans_ = cntsum - cntnum * (mid - 1);
                tmp = cntnum;
                ll = mid + 1;
            } else {
                rr = mid - 1;
            }
        }
          
        if(ans != 100000) {
            cntsum = 0, cntnum = 0;
            query(root[l - 1], root[r], 1, 100000, ans + 1);
        //  cout << cntsum << " " << cntnum << endl;
            ans_ = cntsum - cntnum * ans;
        } else {
            ans_ = 0;
        }
    //  cout << ans << " " << ans_ << " " << cnt << endl;
        printf("%.15f\n", ans - (cnt - ans_) / tmp);
    }
    return 0;
}

 

你可能感兴趣的:(主席树,二分)