Codeforces1305D Kuroni and the Celebration

第一次做交互题,洛谷上可没有交互题做(但是 \(NOI\) 考 随机化算法)

Description

link

给定一棵树,你可以每次询问两个点,返回点的 \(LCA\),要求在\(\lfloor\frac{n}{2} \rfloor\) 次询问内找到树根

\(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]&&deg[j]==1) break;
                ++j;
            }
            k=j+1; 
            while(k<=n)
            {
                if(!vis[k]&&deg[k]==1) break;
                ++k;
            }
            printf("? %lld %lld\n",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\n",i),fflush(stdout),0;
        return 0;
    }
}
signed main(){return yspm::main();} 

猜你喜欢

转载自www.cnblogs.com/yspm/p/12418194.html