Codeforces Round 967 (Div. 2) C题Guess The Tree

题目链接

        令1是根,我们可以一层一层的递推出去。容易知道询问a,b如果结果是c,那么c就是a,b路径上的中点。我们可以先让根1和其他n-1个点都询问一遍,如果返回值是1,那么这些点就是第二层,深度为2的点。我们发现一个c点会对应两层的深节点,比如一条链1 2 3 4,如果询问1 3和1 4返回都会是2,那么我们就让2和3 4分别连一条边,表示3和4是可能和2直接连边的。然后因为第二层我们已经推出来有哪些点了,再去遍历第二层与他们可能的点,然后就推出来第三层的点了。然后一直推下去,就结束了。

        不会算用了多少次,反正能过。

#include
using namespace std;
typedef long long ll;
//#define int long long
typedef pair pii;
const int inf=0x3f3f3f3f;
const int N=2e5+10;
const int mod=1e9+7;
#define fi first
#define se second

int n;
vector d[2000],v[2000];

void solve(){
	cin>>n;
	set e;
	for(int i=1;i<=n;i++)
		d[i].clear(),v[i].clear();
	d[1].push_back(1);
	for(int i=2;i<=n;i++){
		cout<<"? "<<1<<' '<>x;
		if(x==1){
			d[2].push_back(i);
			e.insert({1,i});
		}
		else{
			v[x].push_back(i);
		}
	}
	
	for(int i=2;i<=n;i++){
		for(auto &a:d[i]){
			for(auto &b:v[a]){
				cout<<"? "<>x;
				if(x==a){
					int t=a,tt=b;
					if(t>tt) swap(t,tt);
					e.insert({t,tt});
					d[i+1].push_back(b);
				}
				else{
					v[x].push_back(b);
				}
			}
		}
	}
	cout<<"! ";
	for(auto &x:e){
		cout<>t;
	while(t--){
		solve();
	}
	return 0;
}

你可能感兴趣的:(算法)