1. 程式人生 > >2019牛客多校第九場

2019牛客多校第九場

H Cutting Bamboos

題意

給n個高度,每次獨立詢問一個區間\([l,r]\),對於這個區間的所有高度,要求砍\(y\)次剛好全部砍完,問第\(x\)次砍的位置。

分析

  • 可以二分砍的位置,計算出第\(x\)次砍掉的所有高度,進行check,所以問題就轉化為如何求區間\([l,r]\)裡大於某個值的高度差和。
  • 顯然只需要用主席樹維護值域每個數的個數和加和,查詢區間大於某個值\(x\)的加和,再減去大於\(x\)的個數乘以\(x\),即可。

程式碼

#include <bits/stdc++.h>
using namespace std;
#define mid (l+r)/2
typedef long long ll;
typedef double db;
typedef pair<ll,ll> pll;
const int N=2e5+50;
const db eps=1e-8;
int n,q;
ll h[N],p[N];
int l,r;
ll x,y;
int cnt,tr[N],lr[N*40],rr[N*40];
ll num[N*40],sum[N*40];
int build(int l,int r){
    int rt=++cnt;
    sum[rt]=num[rt]=0;
    if(l==r){
        return rt;
    }
    lr[rt]=build(l,mid);
    rr[rt]=build(mid+1,r);
    return rt;
}
int insert(int pre,int l,int r,int v){
    int rt=++cnt;
    lr[rt]=lr[pre];
    rr[rt]=rr[pre];
    num[rt]=num[pre]+1;
    sum[rt]=sum[pre]+v;
    if(l==r){
        return rt;
    }
    if(v<=mid){
        lr[rt]=insert(lr[pre],l,mid,v);
    }else{
        rr[rt]=insert(rr[pre],mid+1,r,v);
    }
    return rt;
}
//查詢區間大於等於q的h個數和總和
pll query(int u,int v,int l,int r,int q){
    if(l>=q){
        return {num[v]-num[u],sum[v]-sum[u]};
    }
    if(q<=mid){
        auto p=query(lr[u],lr[v],l,mid,q);
        return {p.first+num[rr[v]]-num[rr[u]],p.second+sum[rr[v]]-sum[rr[u]]};
    }else{
        return query(rr[u],rr[v],mid+1,r,q);
    }
}
int main(){
//    freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&q);
    ll mx=0;
    for(int i=1;i<=n;i++){
        scanf("%lld",&h[i]);
        mx=max(mx,h[i]);
        p[i]=p[i-1]+h[i];
    }
    tr[0]=build(1,mx);
    for(int i=1;i<=n;i++){
        tr[i]=insert(tr[i-1],1,mx,h[i]);
    }
    for(int i=0;i<q;i++){
        scanf("%d%d%lld%lld",&l,&r,&x,&y);
        db ned=(p[r]-p[l-1])*1.0/y*x;
        db L=0.0,R=mx*1.0;
        while(L+eps<=R){
            db M=(L+R)/2;
            auto t=query(tr[l-1],tr[r],1,mx,int(ceil(M)));
            db k=t.second*1.0-t.first*M;
            if(k<ned){
                R=M-eps;
            }else{
                L=M+eps;
            }
        }
        printf("%.12lf\n",L);
    }
    return 0;
}