链接:https://ac.nowcoder.com/acm/contest/889/H
来源:牛客网
#include
using namespace std;
#define maxn 200010
typedef long long ll;
const double eps=1e-6;
struct Tree{
ll l,r,sum;
ll ans;
}tree[maxn*40];
ll a[maxn],b[maxn],sum[maxn];
ll n,m,rt[maxn],tot=0,cnt=0;
void build(int l,int r,ll &rt){
rt=++tot;
tree[rt].sum=0;
tree[rt].ans=0;
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,tree[rt].l);
build(mid+1,r,tree[rt].r);
}
void update(int l,int r,int c,int lrt,ll &rt){
rt=++tot;
tree[rt].l=tree[lrt].l;
tree[rt].r=tree[lrt].r;
tree[rt].sum=tree[lrt].sum+1;
tree[rt].ans=tree[lrt].ans+b[c];
if(l==r) return;
int mid=(l+r)>>1;
if(c<=mid) update(l,mid,c,tree[lrt].l,tree[rt].l);
else update(mid+1,r,c,tree[lrt].r,tree[rt].r);
}
int query(int L,int R,int l,int r,int k){
if(l==r) return b[l];
int mid=(l+r)>>1;
int ret=tree[tree[R].l].sum-tree[tree[L].l].sum; //表示rt[L]~rt[R]这个区间内左子树更新了多少个节点
if(k<=ret) return query(tree[L].l,tree[R].l,l,mid,k);
else return query(tree[L].r,tree[R].r,mid+1,r,k-ret);
}
ll query_sum(int L,int R,int l,int r,int k){//求前k小的和
if(l==r) return 1ll*k*b[l];
int mid=(l+r)>>1;
int ret=tree[tree[R].l].sum-tree[tree[L].l].sum;
if(k<=ret) return query_sum(tree[L].l,tree[R].l,l,mid,k);
else{
return tree[tree[R].l].ans-tree[tree[L].l].ans+query_sum(tree[L].r,tree[R].r,mid+1,r,k-ret);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i]; b[i]=a[i];
sum[i]=sum[i-1]+a[i];
}
sort(b+1,b+n+1);
int cnt=unique(b+1,b+n+1)-(b+1);
build(1,cnt,rt[0]);
for(int i=1;i<=n;i++){
int ret=lower_bound(b+1,b+cnt+1,a[i])-b;
update(1,cnt,ret,rt[i-1],rt[i]);
}
while(m--){
ll l,r,x,y; cin>>l>>r>>x>>y;
double cutpart=double(sum[r]-sum[l-1])/y*x;
ll L=0,R=r-l+1,K=0,ret=0; ll ans=0,res=0;
while(L<=R){
ll mid=(L+R)>>1;
ret=query(rt[l-1],rt[r],1,cnt,mid);
ans=query_sum(rt[l-1],rt[r],1,cnt,mid);
res=sum[r]-sum[l-1]-ans-(r-l+1-mid)*ret;
if((double)res-eps>=cutpart){
K=mid; L=mid+1;
}
else R=mid-1;
}
double ans_sum=ret+((double)res-cutpart)/(r-l-K+1);
printf("%.10lf\n",ans_sum);
}
return 0;
}