CF431E Chemistry Experiment

题目

CF431E Chemistry Experiment

分析

线段树上二分,二分答案,线段树。

首先,我们的目的是要求出尽可能小的最大体积,这显然是可以二分后直接判断的。

但是这样是 \(2\log\) 的,我们可以直接考虑线段树上二分。

可是这样就需要实数的线段树上二分了吗?并不是。

我们考虑求答案的过程:先把要选的试管全部调整到同一个体积,再同时给所有的试管平均倒水。

显然,因为我们的修改操作只会出现整数的体积,所以这个调整到的体积一定是一个整数!

所以我们可以考虑并不直接线段树上二分出答案,而是二分出这个调整到的高度!

二分过程如下,每次先重置 \(SIZE,SUM=0\) :

其中 \(sum\) 表示值域区间内水的体积和,\(siz\) 表示值域区间内试管的个数。

\(SUM\) 表示左侧总的水的体积和,\(SIZE\) 表示左侧总的试管个数

ll SIZE,SUM;
ll Query(int x,int l,int r,ll lim){
	if(!x) return l;
	if(l==r) return SIZE+=siz(x),SUM+=sum(x),l;
	int mid=l+r>>1,MID=mid+1;//注意MID
	ll res=1ll*(siz(ls(x))+SIZE)*mid-(sum(ls(x))+SUM);
	if(res>=lim) return Query(ls(x),l,mid,lim);
	else return SIZE+=siz(ls(x)),SUM+=sum(ls(x)),Query(rs(x),mid+1,r,lim); 
}

接下来就是同时往上调整:

else{
	read(l);//l是要分配的体积
    SIZE=SUM=0;
	int height=Query(Root,0,1e9,l);
	l=l-(SIZE*height-SUM);//现在l是多余的拿来分配的体积
	double Ans=(double)height+1.0*(double)l/(double)(SIZE);//加上多增加的高度
	printf("%.5lf\n",Ans);
}

那么就结束了,这里我们通过调整二分的对象规避了实数的线段树上二分。

时间复杂度 \(O(n\log n)\) 。

代码

跑得比较快。

#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void read(T &x){
	x=0;bool f=false;char ch=getchar();
	while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
	while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template<typename T>
inline void write(T x){
	if(x<0) x=-x,putchar('-');
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define ll long long
#define ull unsigned long long
#define inc(x,y,mod) (((x)+(y))>=(mod)?(x)+(y)-(mod):(x)+(y))
#define dec(x,y,mod) ((x)-(y)<0?(x)-(y)+(mod):(x)-(y))
#define rep(i,x,y) for(register int i=(x);i<=(y);i++)
#define dep(i,y,x) for(register int i=(y);i>=(x);i--)
const int N=1e5+5,M=2e5+5,MOD=1e9+7;
int n,m,h[N],cur;
struct SGT{
	int siz,ls,rs;
	ll sum;
	#define ls(x) t[x].ls
	#define rs(x) t[x].rs
	#define sum(x) t[x].sum
	#define siz(x) t[x].siz
}t[N<<6];
void Modify(int &x,int l,int r,int pos,int v){
	if(!x) x=++cur;
	siz(x)+=v,sum(x)+=v*pos;
	if(l==r) return ;
	int mid=l+r>>1;
	if(pos<=mid) Modify(ls(x),l,mid,pos,v);
	else Modify(rs(x),mid+1,r,pos,v);
	return ;
}
ll SIZE,SUM;
ll Query(int x,int l,int r,ll lim){
	if(!x) return l;
	if(l==r) return SIZE+=siz(x),SUM+=sum(x),l;
	int mid=l+r>>1,MID=mid+1;
	ll res=1ll*(siz(ls(x))+SIZE)*MID-(sum(ls(x))+SUM);
	if(res>=lim) return Query(ls(x),l,mid,lim);
	else return SIZE+=siz(ls(x)),SUM+=sum(ls(x)),Query(rs(x),mid+1,r,lim); 
}
int Root;
signed main(){
	read(n);read(m);
	rep(i,1,n) read(h[i]),Modify(Root,0,1e9,h[i],1);
	while(m--){
		ll op,l,r;
		read(op);
		if(op==1) read(l),read(r),Modify(Root,0,1e9,h[l],-1),Modify(Root,0,1e9,(h[l]=r),1);
		else{
			read(l);SIZE=SUM=0;
			int height=Query(Root,0,1e9,l);
			l=l-(SIZE*height-SUM);
			double Ans=(double)height+1.0*(double)l/(double)(SIZE);
			printf("%.5lf\n",Ans);
		}
	}
	
	return 0;
}
上一篇:使用nsenter进入docker容器后端报错 mesg: ttyname failed: No such file or directory


下一篇:feign在服务间传递header