由于太蒻只能被吊打
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;
}