Cutting Bamboos(牛客多校第九场H主席树+二分+思维)

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

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

.

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.
题意:有n棵树,每棵树有高度hi。有m次操作,每次要从l到r砍树,每次砍相同的总高度,砍y次砍完。问砍到第x次的时候该砍哪儿。
看到l到r,不自觉的就想到线段树,主席树等等。
对于l到r区间内的树,总高度我们是知道的,求一个前缀就可以求出来。砍y次砍完,那么我们每一次砍树的总高度我们是知道的。砍掉x次之后剩余的树的总高度我们也是可以求出来的。第x次该砍哪儿,我们二分去找这个高度。找出来之后,我们可以求出来低于这个高度的树的数量和总高度(主席树),那么我们就能求出来根据这个高度求出砍完之后剩余的树高度,我们可以去和标准的答案去比较。
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define esp 1e-10
using namespace std;
 
const int maxx=2e5+100;
struct node{
    int l;
    int r;
    ll sum;
    ll num;
}p[maxx*40];
ll h[maxx],sum[maxx],sumh;
int root[maxx];
int n,m,tot,num;
 
inline int build(int l,int r)
{
    int cur=++tot;
    p[cur].num=p[cur].sum=0;
    if(l==r) return cur;
    int mid=l+r>>1;
    p[cur].l=build(l,mid);
    p[cur].r=build(mid+1,r);
    return cur;
}
inline int update(int rot,int l,int r,ll H)
{
    int cur=++tot;
    p[cur]=p[rot];
    p[cur].num+=1;
    p[cur].sum+=H;
    if(l==r) return cur;
    int mid=l+r>>1;
    if(H<=mid) p[cur].l=update(p[rot].l,l,mid,H);
    else p[cur].r=update(p[rot].r,mid+1,r,H);
    return cur;
}
inline void query(int lrot,int rrot,int l,int r,ll H)
{
    if(l>H) return ;
    if(r<=H)
    {
        num+=(p[rrot].num-p[lrot].num);
        sumh+=(p[rrot].sum-p[lrot].sum);
        return ;
    }
    int mid=l+r>>1;
    query(p[lrot].l,p[rrot].l,l,mid,H);
    query(p[lrot].r,p[rrot].r,mid+1,r,H);
}
int main()
{
    int L,R,x,y;
    while(~scanf("%d%d",&n,&m))
    {
        tot=0;
        root[0]=build(1,200000);
        for(int i=1;i<=n;i++) scanf("%d",&h[i]),sum[i]=sum[i-1]+h[i];
        for(int i=1;i<=n;i++) root[i]=update(root[i-1],1,200000,h[i]);
        while(m--)
        {
            scanf("%d%d%d%d",&L,&R,&x,&y);
            double l=0,r=1e5;
            while(r-l>esp)
            {
                double mid=(l+r)/2;
                num=0,sumh=0;
                query(root[L-1],root[R],1,200000,(ll)mid);//统计比mid低的树的个数和总高度
                int cnt=(R-L+1)-num;//大于mid的树的个数
                double H=1.0*(sum[R]-sum[L-1])/(1.0*y);//每砍完一刀应该砍得总高度
                double s=mid*cnt+sumh;
                if(H*(y-x)<s) r=mid;
                else l=mid;
            }
            printf("%.15lf\n",l);
        }
    }
    return 0;
}

努力加油a啊,(o)/~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值