题解:[COCI 2024/2025 #3] 处理器 / Procesor
我们可以用
然而这题还要求出类似次小值、第三小值等等,所以我们需要保留比较过程中的信息。
大小关系常常用图论描述,如果
先不管打擂台的顺序和方式是怎样的,我们先整理本题的思路:
- 加入一段数后,先打擂台求出这一段的最小值。
- 与之前剩下的数中可能的最小值放在一起再打一次擂台,求出当前答案
ans 。 - 把
ans 删除,将ans 的儿子设为可能的最小值。
设
第一步是
第三步带来的候选点的总数是
打擂台的过程无法优化,我们只能尝试减少第三步带来的候选点数。在树上这体现为
我们采用类似线段树的结构进行打擂台,求出左区间和右区间的最小值,再将它们放一起打擂台。
这样每个点只会进行
#include<bits/stdc++.h>
#define ll long long
#define mid ((l+r)>>1)
#define rep(x,y,z) for(int x=(y);x<=(z);x++)
#define repn(x) rep(x,1,n)
#define pb push_back
inline int read(){int s=0,w=1;char c=getchar();while(c<48||c>57) {if(c=='-') w=-1;c=getchar();}while(c>=48&&c<=57)s=(s<<1)+(s<<3)+c-48,c=getchar();return s*w;}
using namespace std;
const int N=3e5+5;
int n,a[N],pr[N];
inline int cmp(int a,int b){
cout <<"? "<<a<<' '<<b<<endl;
return read();
}
int deg[N];
map<int,int>Nw;
vector<int>p[N];
inline int solve(int l,int r){
if(l==r)return l;
int a=solve(l,mid),b=solve(mid+1,r);
if(cmp(a,b))return p[b].pb(a),b;
return p[a].pb(b),a;
}
int st[N],tp;
inline int Sol(int l,int r){
if(l==r)return st[l];
int a=Sol(l,mid),b=Sol(mid+1,r);
if(cmp(a,b))return p[b].pb(a),b;
return p[a].pb(b),a;
}
inline void Solve(){
tp=0;
for(auto x:Nw)st[++tp]=x.first;
int now=Sol(1,tp);
Nw.clear();
for(auto y:p[now])Nw[y]=1;
cout <<"! "<<now<<endl;
}
inline void Main(){
n=read();
repn(i){
a[i]=read(),pr[i]=pr[i-1]+a[i];
int l=pr[i-1]+1,r=pr[i];
Nw[solve(l,r)]=1;
Solve();
}
}
signed main(){
int T=1;
while(T--)Main();
return 0;
}