第一次做交互题,洛谷上可没有交互题做(但是 (NOI) 考 随机化算法)
Description
给定一棵树,你可以每次询问两个点,返回点的 (LCA),要求在(lfloorfrac{n}{2} floor) 次询问内找到树根
(n le 2000)
Solution
这题考场上有点慌了,没有仔细思考
其实有一些性质可以运用的
首先,我们每一次找到叶节点,此处可以考虑用度数解决
然后询问两个叶节点的根(设叶节点为 (u) , (v) )
如果这个(LCA) 是两个点之一,直接给答案(代码里没有直接输出)
否则,我们可以考虑把LCA的所有子树砍掉,让 (LCA) 是变成叶节点
这个流程我觉得正确性挺显然
由于数据范围较小,所以我们可以直接暴力地实现一些流程(找叶子)
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=2010;
int head[N],n,cnt,deg[N],now,vis[N];
struct node{
int nxt,to;
}e[N<<1];
inline void add(int u,int v)
{
e[++cnt].nxt=head[u]; e[cnt].to=v;
return head[u]=cnt,void();
}
inline void dfs(int x,int fa)
{
if(x==fa||vis[x]) return ;
vis[x]=1; now--;
for(int i=head[x];i;i=e[i].nxt) dfs(e[i].to,fa);
return ;
}
signed main()
{
now=n=read();
for(int i=1;i<n;++i)
{
int x=read(),y=read();
add(x,y); add(y,x);
deg[x]++; deg[y]++;
}
for(int i=1;i<=n;++i)
{
int j=1,k;
while(j<=n)
{
if(!vis[j]&°[j]==1) break;
++j;
}
k=j+1;
while(k<=n)
{
if(!vis[k]&°[k]==1) break;
++k;
}
printf("? %lld %lld
",j,k); fflush(stdout);
int w=read(); dfs(j,w); dfs(k,w);
if(w==j||w==k) deg[w]--;
else deg[w]-=2;
if(now==1) break;
}
for(int i=1;i<=n;++i) if(!vis[i]) return printf("! %lld
",i),fflush(stdout),0;
return 0;
}
}
signed main(){return yspm::main();}