把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF431E Chemistry Experiment

题面传送门
题解里居然没有写线段树上二分的,来交一发。
维护一颗权值线段树,以\(h_i\)为下标,主要维护两个值,是元素个数和元素和。
那么当前点\(m\)可以判断左边的节点数\(\times m-\)左边的元素和是否大于当前的水量来考虑走左边还是右边。走到最后一个节点时计算剩下的水量,然后均摊给每一个试管。
时间复杂度\(O(nloga)\),一点不卡常。
代码实现:

#include<cstdio>
#define l(x) f[x].l
#define r(x) f[x].r
using namespace std;
int n,m,k,y,x,tot,pus,root,cnt,sx,a[100039];
long long z;
struct tree{int l,r,siz;long long f;}f[10000039];
inline void get(long long x,int y,long long l,long long r,int &now){
	if(!now) now=++cnt;
	if(l==r) {f[now].f+=x*y;f[now].siz+=y;return ;}
	double m=(l+r)/2;
	if(x<=m) get(x,y,l,m,l(now));
	else get(x,y,m+1,r,r(now));
	f[now].f=f[l(now)].f+f[r(now)].f;
	f[now].siz=f[l(now)].siz+f[r(now)].siz;
}
inline double find(long long x,long long l,long long r,int now){
	long long siz=0;long long fs=0;
	while(l!=r){
		double m=(l+r)/2;
		if(x>=m*(siz+f[l(now)].siz)-fs-f[l(now)].f)l=m+1,fs+=f[l(now)].f,siz+=f[l(now)].siz,now=r(now);
		else r=m,now=l(now);
	}
	return l+(x-(l*(siz+f[l(now)].siz)-fs-f[l(now)].f))*1.0/siz;
}
inline void read(int &x){
	char s=getchar();x=0;
	while(s<'0'||s>'9') s=getchar();
	while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
int main(){
//	freopen("1.in","r",stdin);
	register int i;
	read(n);read(m);
	for(i=1;i<=n;i++) read(a[i]),get(a[i],1,0,1e13,root);
	for(i=1;i<=m;i++){
		read(sx);
		if(sx==1) read(x),read(y),get(a[x],-1,0,1e13,root),a[x]=y,get(a[x],1,0,1e13,root);
		else scanf("%lld",&z),printf("%.5lf\n",find(z,0,1e13,root));
	}
}
posted @ 2020-11-03 20:04  275307894a  阅读(79)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end