描述:n个试管,给你每个试管装有的水的高度,q次询问,1)把一个试管的水量改成x,2)假设你可以选择任意的一些试管,一共添加v高度的水,问添加了水的这些试管,添加水后的最大高度的最小值。
最小化最大值,首先想二分答案,假设添加水后的最大高度为d,再看d能不能达到。
水柱高度小于d的试管数量记为cnt,水总和为sum。
可以往这些试管中加的水量:v1=d*cnt-sum,若v1>=v,则d或许可以更小,否则这些试管加不了v高度的水,加完后高度就大于d,所以d要往上调。
现在问题变成了如何动态维护cnt和sum的问题,这用线段树很容易做到。
首先将用到的所有高度离散化,线段树区间是高度区间,然后就可以愉快维护某个高度区间的cnt和sum了。
单点修改logn;二分logn,每次检查:先二分离散化的后高度的位置logn,查询cnt和sum logn => log2n。总的时间复杂度 qlog2n。
其实这用树状数组也可以做到。用一个数组b维护每个高度的cnt,用一个数组c维护每个高度的sum。因为这只涉及到单点修改和区间和。
#include<bits/stdc++.h>
using namespace std;
#define eps 1e-5
#define x first
#define y second
const int N=1e5+10,M=2*N;
typedef long long ll;
typedef pair<ll,ll> pll;
int n,q;
int h[N];
struct node{
int op;
ll a;
int b;
}input[N];
struct node2{
ll cnt,sum;
}tr[M<<2];
vector<int> alls;
int find(int x){
return lower_bound(alls.begin(),alls.end(),x)-alls.begin();
}
void modify(int p, int l,int r,int i,int x,int y){
if(l==r){
tr[p].cnt+=x;
tr[p].sum+=y;
return;
}
int mid=(l+r)>>1;
if(i<=mid) modify(p*2,l,mid,i,x,y);
else modify(p*2+1,mid+1,r,i,x,y);
tr[p].cnt=tr[p*2].cnt+tr[p*2+1].cnt;
tr[p].sum=tr[p*2].sum+tr[p*2+1].sum;
}
pll ask(int p,int l,int r,int L,int R){
if(L<=l&&r<=R){
return {tr[p].cnt,tr[p].sum};
}
int mid=(l+r)>>1;
ll cnt=0,sum=0;
if(L<=mid) {
auto t=ask(p*2,l,mid,L,R);
cnt+=t.x;
sum+=t.y;
}
if(R>=mid+1){
auto t=ask(p*2+1,mid+1,r,L,R);
cnt+=t.x;
sum+=t.y;
}
return {cnt,sum};
}
bool check(double x,ll v){
int d=x>alls.back()?alls.back():x;
int i=find(d);
auto t=ask(1,0,alls.size()-1,0,i);
double v1=x*t.x-t.y;
if(v1>=v) return true;
return false;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&h[i]);
alls.push_back(h[i]);
}
for(int i=0;i<q;i++){
int op;
scanf("%d",&op);
if(op==1){
ll a;
int b;
scanf("%lld%d",&a,&b);
input[i]={op,a,b};
alls.push_back(b);
}
else{
ll a;
scanf("%lld",&a);
input[i]={op,a,0};
}
}
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
for(int i=1;i<=n;i++){
int j=find(h[i]);
modify(1,0,alls.size()-1,j,1,h[i]);
}
for(int i=0;i<q;i++){
auto u=input[i];
if(u.op==1){
int j=find(h[u.a]);
modify(1,0,alls.size()-1,j,-1,-h[u.a]);
h[u.a]=u.b;
j=find(u.b);
modify(1,0,alls.size()-1,j,1,u.b);
}
else{
double lb=0,ub=1e24+10;
while(ub-lb>=eps){
double mid=(lb+ub)/2;
check(mid,u.a)?ub=mid:lb=mid;
}
printf("%.5lf\n",ub);
}
}
return 0;
}
邪恶的小鬼,不要让我失望,老夫这就!
gxcpc佬吗