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);
}
posted @ 2023-10-01 21:05  pidan007  阅读(11)  评论(0编辑  收藏  举报