• CF431E Chemistry Experiment


    题目

    CF431E Chemistry Experiment

    分析

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

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

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

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

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

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

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

    二分过程如下,每次先重置 (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
    ",Ans);
    }
    

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

    时间复杂度 (O(nlog 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
    ",Ans);
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    《舌尖上的中国》精彩故事
    5年前的笔试题目
    遍历物理模型中的所有表,将表名、表代码、字段名、字段代码全部由小写改成大写
    MongoDB下载文件 百度盘共享
    认识MEAN开发框架[转]
    智能油田
    排课相关参数设置
    spring获取所有被装配类工具
    oracle常用sql集锦
    关于使用easyUI遇到过的一些坑
  • 原文地址:https://www.cnblogs.com/Akmaey/p/15271643.html
Copyright © 2020-2023  润新知