题目链接:https://codeforces.com/contest/1592/problem/D
一般交互题常见的思路 1是二分 2是分块
这道题可以先跑一遍欧拉序,将结点保存在a数组内,之后我们就可以二分a数内连续的一端(这个连续的一段就代表着树内连续的一条边) ,找出的l,r就是题目的答案。
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define rep(x, y, z) for (int x = y; x <= z; x++)
#define dec(x, y, z) for (int x = y; x >= z; x--)
const int N = 10010, mod = 1e9 + 7;
const double expp = 1e-10;
typedef long long ll;
//------------------------
int n;
vector<int> G[N];
vector<int> ve;
int a[N];
int cnt;
void add(int a,int b){
G[a].push_back(b);
}
void dfs(int u,int fa){
for(auto v:G[u]){
if(v == fa) continue;
a[++cnt] = v;
dfs(v,u);
a[++cnt] = u;
}
}
int query(){
sort(ve.begin(),ve.end());
ve.erase(unique(ve.begin(),ve.end()),ve.end());
cout<<"? "<<(int)ve.size()<<" ";
rep(i,0,(int)ve.size()-1) cout<<ve[i]<<" ";
cout<<endl;
int ans;
cin>>ans;
return ans;
}
int main(){
cin>>n;
rep(i,1,n-1){
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
a[++cnt] = 1;
dfs(1,0);
rep(i,1,cnt) ve.push_back(a[i]);
int maxx = query();
int l=1,r = cnt;
while(l+1<r){
int mid = l+r >> 1;
ve.clear();
rep(i,l,mid) ve.push_back(a[i]);
if(query() < maxx ) l = mid;
else r = mid;
}
cout<<"! "<<a[l]<<" "<<a[r]<<endl;
cout.flush();
return 0;
}