A Certain Forbidden Index
不错的交互题。
实际上这题是构造。
理性分析,询问次数的一个粗略下界是 \(\frac{n}{2}\) 的,因为每个叶子都一定要问到,而一个线段树区间询问至多包含 \(2\) 个叶子
显然 \([1,n],[1,1],[n,n]\) 必须单独问
为了尽量节省次数,我们考虑对叶子和非叶子结点匹配,这样找到之后就可以仅用一次询问找到答案
手玩亿下,发现只要在线段树分裂成两个儿子的时候将左儿子与 \(mid+1\) 匹配,右儿子与 \(mid\) 匹配即可
然后把两个对拼成一个桥状的区间,就可以取到下界
然而这个 🤡 连 T1 都不会,快来嘲讽这个 🤡。。
点击查看代码
#include<bits/stdc++.h>
#define ls (k<<1)
#define rs (k<<1|1)
#define mid ((l+r)>>1)
using namespace std;
const int maxn=(1<<16)+1;
int N,par[maxn],rev[maxn],match[maxn];
int query(int l,int r);
void Build(int k,int l,int r){
if(l==r)return;
Build(ls,l,mid);
Build(rs,mid+1,r);
par[rev[rs]=mid]=r;
par[rev[ls]=mid+1]=l;
}
void Dliub(int k,int l,int r){
if(l==r)return;
Dliub(ls,l,mid);
Dliub(rs,mid+1,r);
int curl=ls,curr=rs;
while(true){
curl=curl<<1|1;
curr=curr<<1;
if(!rev[curl]||!rev[curr])break;
if(par[rev[curl]]+1==par[rev[curr]]){
match[rev[curl]]=rev[curr];
match[rev[curr]]=rev[curl];
}
}
}
pair<int,int>solve(int k){
N=1<<k;
Build(1,1,N);
Dliub(1,1,N);
for(int i=2;i<N;i++){
int j=match[i];
if(!j){
if((i&1)&&query(par[i],i)){
if(query(i,i))return make_pair(i,i);
return make_pair(par[i],i-1);
}
if(!(i&1)&&query(i,par[i])){
if(query(i,i))return make_pair(i,i);
return make_pair(i+1,par[i]);
}
continue;
}
if(i<j){
if(query(i,j)){
if((i&1)&&query(par[i],i)){
if(query(i,i))return make_pair(i,i);
return make_pair(par[i],i-1);
}
if(!(i&1)&&query(i,par[i])){
if(query(i,i))return make_pair(i,i);
return make_pair(i+1,par[i]);
}
if((j&1)&&query(par[j],j)){
if(query(j,j))return make_pair(j,j);
return make_pair(par[j],j-1);
}
if(!(j&1)&&query(j,par[j])){
if(query(j,j))return make_pair(j,j);
return make_pair(j+1,par[j]);
}
}
}
}
if(query(1,1))return make_pair(1,1);
if(query(N,N))return make_pair(N,N);
return make_pair(1,N);
}