题解:CF2163D2 Diadrash (Hard Version)
首先,这类题有一个经典trick,就是对于一个
对于此题,已知一个集合的
设
红点就是最终答案所在位置,二分选哪个区间即可。
有个细节是答案有可能取在极值点两边,所以最终答案要选择极值点附近两点比较大小。
次数
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int a[N],n,q;
int ask(int l,int r){
cout<<"? "<<l<<" "<<r<<endl;
int ret;
cin>>ret;return ret;
}
int l[N],r[N],m;
signed main(){
ios::sync_with_stdio(false);cin.tie(0);
int T;cin>>T;
while(T--){
cin>>n>>q;
for(int i=1;i<=n;i++)a[i]=i+1;
while(q--){
int l,r;cin>>l>>r;
a[r]=min(a[r],l);
}
int mn=n+1;
for(int i=n;i>=1;i--){
if(a[i]>=mn)a[i]=i+1;
else mn=min(a[i],mn);
}
m=0;
for(int i=1;i<=n;i++)if(a[i]!=i+1)l[++m]=a[i],r[m]=i;//所有有用的区间
int p=0;
for(int i=1<<20;i;i>>=1){
if(p+i<=m&&ask(l[p+i],n)>=ask(1,r[p+i]))p+=i;
}
int ans=0;
if(p!=0)ans=max(ans,ask(l[p],r[p]));
if(p+1<=m)ans=max(ans,ask(l[p+1],r[p+1]));
cout<<"! "<<ans<<endl;
}
return 0;
}