题意:n个竹子,有高度,q次询问,询问之间是独立的,每次查询输入l,r,x,yl,r,x,yl,r,x,y代表砍区间[l,r][l,r][l,r]内的竹子砍y次,最后一次要砍成0,每次砍掉的总长度相同,问第x次砍的高度是多少。
赛中榜有点歪吧,就一直在想j怎么写,H也没怎么看,最后剩20分钟的时候,lt跑过来和我说这个好像可以二分做,然后我就想可以套主席树写,就赶紧写,结果第一次写完的时候少维护了一个东西,然后就快5点了,我写完正好5:01,交了就过了2333。
既然每次要求砍掉的东西都相同,那么就可以直接算出来砍第x次需要砍掉多少,然后只需要二分这个高度,在主席树中查找大于等于这个高度的竹子总和减去个数乘以高度即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
const double epos=1.0e-7;
int a[maxn];
int b[maxn];
int m;
void quchong(int n){
sort(b+1,b+1+n);
m=unique(b+1,+b+1+n)-b-1;
}
int getid(int x){
return lower_bound(b+1,b+1+m,x)-b;
}
struct Tree{
int lc,rc;
ll sum;
ll x;
}tree[maxn*50];
int root[maxn],tot;
int build(int l,int r){
int k=++tot;
tree[k].sum=0;
tree[k].x=0;
if(l==r) return k;
int mid=(l+r)>>1;
tree[k].lc=build(l,mid);
tree[k].rc=build(mid+1,r);
return k;
}
void pushup(int k){
tree[k].sum=tree[tree[k].lc].sum+tree[tree[k].rc].sum;
tree[k].x=tree[tree[k].lc].x+tree[tree[k].rc].x;
}
int updata(int now,int l,int r,int id,int val){
int k=++tot;
tree[k]=tree[now];
if(l==r){
tree[k].sum+=val;
tree[k].x++;
return k;
}
int mid=(l+r)>>1;
if(id<=mid) tree[k].lc=updata(tree[now].lc,l,mid,id,val);
else tree[k].rc=updata(tree[now].rc,mid+1,r,id,val);
pushup(k);
return k;
}
ll myfind(int p,int q,int l,int r,int L,int R){
if(l>=L&&r<=R) return tree[p].sum-tree[q].sum;
int mid=(l+r)>>1;
ll res=0;
if(L<=mid) res+=myfind(tree[p].lc,tree[q].lc,l,mid,L,R);
if(R>mid) res+=myfind(tree[p].rc,tree[q].rc,mid+1,r,L,R);
return res;
}
ll myfind1(int p,int q,int l,int r,int L,int R){
if(l>=L&&r<=R) return tree[p].x-tree[q].x;
int mid=(l+r)>>1;
ll res=0;
if(L<=mid) res+=myfind1(tree[p].lc,tree[q].lc,l,mid,L,R);
if(R>mid) res+=myfind1(tree[p].rc,tree[q].rc,mid+1,r,L,R);
return res;
}
double check(int l,int r,double x){
double res=0;
int id=getid(ceil(x));
if(id==m+1) return 0;
return myfind(root[r],root[l-1],1,m,id,m)-myfind1(root[r],root[l-1],1,m,id,m)*x;
}
ll sum[maxn];
int main(){
int n,q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
b[i]=a[i];
}
quchong(n);
root[0]=build(1,m);
for(int i=1;i<=n;++i)
root[i]=updata(root[i-1],1,m,getid(a[i]),a[i]);
int ll,rr,x,y;
double l,r,mid;
while(q--){
scanf("%d%d%d%d",&ll,&rr,&x,&y);
double zong=(sum[rr]-sum[ll-1])*1.0/y*x;
l=0,r=1000000000;
while(r-l>epos){
mid=(l+r)/2;
double xx=check(ll,rr,mid);
if(xx>zong) l=mid;
else r=mid;
}
printf("%.10f\n",r);
}
return 0;
}