zoukankan      html  css  js  c++  java
  • 树状数组+离散化+二分——[省选联考 2020 A/B 卷] 冰火战士

    由于太蒻只能被吊打

    problem(luogu链接 loj链接

    假设战斗温度为\(k\),则对于每一个冰战士\(ice_i\)\(i\)战士能出战的条件为\(ice_i\leq k\),对于每一个火战士\(fire_i\)\(i\)战士能出战的条件是\(fire_i \geq k\),现在你需要找一个最适温度\(k\),使得\(\min(\sum{ice_i},\sum{fire_i})\)的两倍最大。

    solution

    可以知道,最终答案的温度一定是某个战士的温度(因为温度最适前提下越高越好),所以对数据进行离散化便于处理。

    	sort(val+1,val+cnt_val+1);
    	cnt_val=unique(val+1,val+cnt_val+1)-(val+1);
    	for(int i=1;i<=m;i++)	e[i].x=lower_bound(val+1,val+cnt_val+1,e[i].x)-val;
    

    我们定义两个函数\(ice(i)、fire(i)\),其中的每一个元素,\(ice(i)\)只升不降,\(fire(i)\)只降不升,即依题意战士顺序排序,在同一直角坐标系中,可以发现当两函数图像相交时有答案为最大值(不能理解就手动模拟),但实际上两函数图像不一定相交(或者交点不一定是整数),所以有两个可能的最适温度\(k\)一个是\(k_1=max(\sum ice_i<\sum fire_i)\)另一个是\(k_2=min(\sum ice_i \geq \sum fire_i)\)

    那如何找 \(k\)呢,第一反应肯定是二分,我们已经有了每一个战士的温度,对于得到的这个数列\(k_i\)(从小到大排序过),将所有\(k_i \geq ice_i\)的价值加上\(ice_i\)的能量,所有\(k_i \leq fire_i\)的价值加上\(fire_i\)的能量。需要单点加,区间查询,考虑线段树或是树状数组。继续观察,发现\(k_2\)会等于\(k_1+1\),那我们需要一次二分求出\(k_1\),在将它加1得到\(k_2\),再一次计算得到\(k_2\)温度下对应的能量值,比较之后选较大,但是发现如果是\(k_2\),就有可能还有更大的\(k_2\)满足条件,则根据得到的最大能量值再求一个\(k_3\),取最大就好了。

    一次查询可能需要三次二分求答案,用线段树的时间复杂度为\(O(n\log n)\),但是由于常数大可能过不去,那么考虑使用树状数组进行求解,树状数组上的二分(我认为)就是需要的加上不要的跳过,一直迭代即可。大概是这样的。

    inline int find1(){
    	int p=0,s=-delta_fire;
    	for(int i=20;i>=0;i--){
    		if(p+(1<<i)>cnt_val)	continue;
    		int ls=s+ice[p+(1<<i)]-fire[p+(1<<i)];
    		if(ls<0){
    			s=ls;
    			p+=(1<<i);
    		}
    	}
    	return p;
    }
    

    树状数组一般都是从一个点开始往后加,那对于\(fire_i\)需要加在前缀就记录一个偏移量\(detla\),在统计能量的时候先把它加上就好啦。

    inline void add_fire(int pos,int energy){
    	delta_fire+=energy;
    	for(int i=pos+1;i<=cnt_val;i+=lowbit(i))
    		fire[i]-=energy;
    }
    

    看不懂就理解一下\(code\)好了qwq

    code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<utility>
    using namespace std;
    const int M=2e6+5;
    struct node{
    	int t,x,y;
    }e[M];
    int m,cnt_val,val[M],ice[M],fire[M],delta_fire;
    
    inline int read(){
    	char ch;
    	int res,fl=1;
    	while((ch=getchar())&&(ch<'0'||ch>'9'))
    		if(ch=='-')	fl=-1;
    	res=ch-'0';
    	while((ch=getchar())&&ch>='0'&&ch<='9')
    		res=res*10+ch-'0';
    	return res*fl;
    }
    
    inline int lowbit(int x){	return x&(-x);}
    
    inline void add_ice(int pos,int energy){
    	for(int i=pos;i<=cnt_val;i+=lowbit(i))
    		ice[i]+=energy;
    }
    
    inline void add_fire(int pos,int energy){
    	delta_fire+=energy;
    	for(int i=pos+1;i<=cnt_val;i+=lowbit(i))
    		fire[i]-=energy;
    }
    
    inline int find1(){
    	int p=0,s=-delta_fire;
    	for(int i=20;i>=0;i--){
    		if(p+(1<<i)>cnt_val)	continue;
    		int ls=s+ice[p+(1<<i)]-fire[p+(1<<i)];
    		if(ls<0){
    			s=ls;
    			p+=(1<<i);
    		}
    	}
    	return p;
    }
    
    inline int query(int pos){
    	int sum_ice=0,sum_fire=delta_fire;
    	for(int p=pos;p;p-=lowbit(p)){
    		sum_ice+=ice[p];
    		sum_fire+=fire[p];
    	}
    	return min(sum_ice,sum_fire);
    }
    
    inline int find2(int num){
    	int p=0,sum_ice=0,sum_fire=delta_fire;
    	for(int i=20;i>=0;i--){
    		if(p+(1<<i)>cnt_val)	continue;
    		int now_ice=sum_ice+ice[p+(1<<i)];
    		int now_fire=sum_fire+fire[p+(1<<i)];
    		if(now_ice<now_fire){
    			sum_ice=now_ice;
    			sum_fire=now_fire;
    			p+=(1<<i);
    		}else	if(min(now_ice,now_fire)==num){
    			sum_ice=now_ice;
    			sum_fire=now_fire;
    			p+=(1<<i);
    		}
    	}
    	return p;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("icefire2.in","r",stdin);
    	freopen("icefire.out","w",stdout);
    #endif
    	m=read();
    	for(int i=1;i<=m;i++){
    		int tp;
    		tp=read();
    		if(tp==1){
    			e[i].t=read(),e[i].x=read(),e[i].y=read();
    			val[++cnt_val]=e[i].x;
    		}else{
    			int k;k=read();
    			e[i].x=e[k].x;
    			e[i].t=e[k].t;
    			e[i].y=-e[k].y;
    		}
    	}
    	sort(val+1,val+cnt_val+1);
    	cnt_val=unique(val+1,val+cnt_val+1)-(val+1);
    	for(int i=1;i<=m;i++)	e[i].x=lower_bound(val+1,val+cnt_val+1,e[i].x)-val;
    	for(int i=1;i<=m;i++){
    		if(e[i].t==0)	add_ice(e[i].x,e[i].y);
    		else	add_fire(e[i].x,e[i].y);
    		int p1=find1();
    		pair <int,int> res1=make_pair(-1,-1);
    		if(p1>0)	res1=make_pair(query(p1),p1);
    		pair <int,int> res2=make_pair(-1,-1);
    		if(p1<cnt_val){
    			int s2=query(p1+1);
    			int p2=find2(s2);
    			res2=make_pair(s2,p2);
    		}
    		pair <int,int> res=max(res1,res2);
    		if(res.first==0)
    			printf("Peace\n");
    		else
    			printf("%d %d\n",val[res.second],res.first*2);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Paperfolding HDU
    I
    2020年8月11日第一次组队训练
    2018ICPC南京I. Magic Potion
    【贪心】纪念品分组
    【贪心】删数问题
    【排序】排名
    小X与队列
    B.T.B.F.
    2018浙江理工大学迎新赛——决赛
  • 原文地址:https://www.cnblogs.com/FridayZ/p/13234456.html
Copyright © 2011-2022 走看看