CF431E Chemistry Experiment

题面传送门
题解里居然没有写线段树上二分的,来交一发。
维护一颗权值线段树,以 h i h_i hi为下标,主要维护两个值,是元素个数和元素和。
那么当前点 m m m可以判断左边的节点数 × m − \times m- ×m左边的元素和是否大于当前的水量来考虑走左边还是右边。走到最后一个节点时计算剩下的水量,然后均摊给每一个试管。
时间复杂度 O ( n l o g a ) O(nloga) 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));
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值