题解:[省选联考 2020 A/B 卷] 冰火战士
题意分析
记 \(\mathrm{ice}\) 表示冰系战士,\(\mathrm{fire}\) 表示火系战士。
记 \(\operatorname{ice}(t),\operatorname{fire}(t)\) 分别表示温度为 \(t\) 的时候,能出战的战士的能量总和。这很好用树状数组/线段树维护。就我一个 SB 在模拟赛上认为这是可持久化。
容易发现,双方消耗能量永远相同;因此温度为 \(t\) 时,消耗总能量为 \(2\min(\operatorname{ice}(t),\operatorname{fire}(t))\)。
最终答案即求 \(\min(\operatorname{ice}(t),\operatorname{fire}(t))\) 最大时,\(t\) 的最大值。
根据冰系战士、火系战士的定义,可以发现 \(\operatorname{ice}(t)\) 随 \(t\) 增大而不降,\(\operatorname{fire}(t)\) 随 \(t\) 增大而不增。因此 \(\min(\operatorname{ice}(t),\operatorname{fire}(t))\) 其实是单峰的(存在取值相同的部分),交点即 \(\operatorname{ice}(t)=\operatorname{fire}(t)\) 的点。
普通单峰函数是三分(其实我就写过一次三分),而存在取值相同也不能三分,考虑二分。
二分出一个 \(t=t_0\) 使得 \(\operatorname{ice}(t)<\operatorname{fire}(t)\) 成立且 \(t_0\) 最大。那么最大总能量一定在 \(t=t_0\) 或 \(t=t_0+1\) 的时候取到。(函数是离散的,可能交点不在整点上,两个点都有可能)。
- 若为 \(t=t_0\),则这就是答案,因为 \(t\) 再大的时候就不满足总能量最大。
- 若为 \(t=t_0+1\) 的时候,还需要再次二分找到 \(t=t_0'\) 使得总能量相同,且 \(t_0'\) 最大。
温度需要离散化。
这样的复杂度为 \(\mathcal O\left(q\log^2q\right)\),考虑道时限 \(\text{3s}\),很可以做。
但是据说需要 \(\mathcal O(q\log q)\) 的做法,也很简单,就是倍增查询树状数组/线段树二分。直接去掉二分,充分利用已知信息。
AC 代码
懒,\(\mathcal O\left(q\log^2q\right)\) 写法。luogu 最慢 \(\text{1.83s}\)。
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=2e6;
struct operation{
int op,t,x,y;
}a[N+1];
int n,len,tmp[N+1];
void discrete(){
for(int i=1;i<=n;i++){
if(a[i].op==1){
tmp[++len]=a[i].x;
}
}
sort(tmp+1,tmp+len+1);
len=unique(tmp+1,tmp+len+1)-tmp-1;
for(int i=1;i<=n;i++){
if(a[i].op==1){
a[i].x=lower_bound(tmp+1,tmp+len+1,a[i].x)-tmp;
}
}
}
struct bit{
int t[N+1+1],sum;
int lowbit(int x){
return x&-x;
}
void add(int x,int k){
sum+=k;
while(x<=N){
t[x]+=k;
x+=lowbit(x);
}
}
int query(int x){
if(x<=0){
return 0;
}
int ans=0;
while(x){
ans+=t[x];
x-=lowbit(x);
}
return ans;
}
}ice,fire;
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].op;
switch(a[i].op){
case 1:
cin>>a[i].t>>a[i].x>>a[i].y;
break;
case 2:
cin>>a[i].x;
break;
}
}
discrete();
for(int i=1;i<=n;i++){
if(a[i].op==1){
switch(a[i].t){
case 0:
ice.add(a[i].x,a[i].y);
break;
case 1:
fire.add(a[i].x,a[i].y);
break;
}
}else{
switch(a[a[i].x].t){
case 0:
ice.add(a[a[i].x].x,-a[a[i].x].y);
break;
case 1:
fire.add(a[a[i].x].x,-a[a[i].x].y);
break;
}
}
int l=1,r=len,t=0;
while(l<=r){
int mid=l+r>>1;
if(ice.query(mid)<fire.sum-fire.query(mid-1)){
t=mid;
l=mid+1;
}else{
r=mid-1;
}
}
int ans1=min(ice.query(t),fire.sum-fire.query(t-1));
int ans2=min(ice.query(t+1),fire.sum-fire.query(t));
if(ans1<=0&&ans2<=0){
cout<<"Peace\n";
}else if(ans1>ans2){
cout<<tmp[t]<<' '<<(ans1<<1)<<'\n';
}else{
t++;
int l=t,r=len;
while(l<=r){
int mid=l+r>>1;
if(min(ice.query(mid),fire.sum-fire.query(mid-1))>=ans2){
l=mid+1;
t=mid;
}else{
r=mid-1;
}
}
cout<<tmp[t]<<' '<<(ans2<<1)<<'\n';
}
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号