• CF1370F2The Hidden Pair(Hard Version)【交互题,二分】


    正题

    题目链接:https://www.luogu.com.cn/problem/CF1370F2


    题目大意

    \(T\)组数据,给出\(n\)个点的一棵树,有两个隐藏的关键点。你每次可以询问一个点集,交互库会回答这个点集中的一个点满足它到两个关键点的距离和最小,和这个距离。

    要求在\(11\)次询问内求出这两个关键点。

    \(1\leq T\leq 10,1\leq n\leq 1000\)


    解题思路

    首先第一下不知道干啥就问整张图吧。

    这样我们就得到了一个点\(rt\)和距离\(L\)。这个点\(rt\)一定在关键点\(u,v\)的路径上,且\(L\)表示\(u,v\)之间的距离。

    然后就好搞了,我们以\(rt\)为根,考虑利用这个\(L\)来搞点操作,我们每次选择一个深度\(dep\)然后询问所有这个深度的点的话,如果得到的距离等于\(L\)就表示这个深度有\(u\sim v\)路径上的点。

    也就是我们可以通过二分得到最深的位置,而最深的位置一定是离\(rt\)较远的一个关键点\(u\)

    而我们又知道两个关键点的距离,以\(u\)为根询问一遍深度\(L\)的节点就可以得到\(v\)了。

    二分上界是\(min\{L,dep_{max}\}\),所以次数是\(log(n)+2\leq 12\)。好像多了一次?

    再挖掘一下性质,发现我们找的是离\(rt\)较远的一个关键点,所以这段距离一定是不小于\(\lfloor\frac{L-1}{2}\rfloor\)的,这样就可以少去一次了


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int N=1100;
    struct node{
    	int to,next;
    }a[N<<1];
    int T,n,tot,ls[N],mx;
    vector<int> v[N];char s[10];
    void print(int x)
    {if(x>9)print(x/10);putchar(48+x%10);return;}
    void addl(int x,int y){
    	a[++tot].to=y;
    	a[tot].next=ls[x];
    	ls[x]=tot;return;
    }
    void dfs(int x,int fa,int dep){
    	v[dep].push_back(x);mx=max(mx,dep);
    	for(int i=ls[x];i;i=a[i].next){
    		int y=a[i].to;
    		if(y==fa)continue;
    		dfs(y,x,dep+1);
    	}
    	return;
    }
    int main()
    {
    	scanf("%d",&T);
    	while(T--){
    		memset(ls,0,sizeof(ls));tot=mx=0;
    		for(int i=0;i<=n;i++)v[i].clear();
    		scanf("%d",&n);
    		for(int i=1;i<n;i++){
    			int x,y;
    			scanf("%d%d",&x,&y);
    			addl(x,y);addl(y,x);
    		}
    		printf("? %d ",n);
    		for(int i=1;i<=n;i++)
    			print(i),putchar(' ');
    		putchar('\n');fflush(stdout);
    		int rt,L,u,uu;
    		scanf("%d%d",&rt,&L);
    		dfs(rt,0,0);u=uu=rt;
    		int l=(L-1)/2+1,r=min(L,mx);
    		while(l<=r){
    			int mid=(l+r)>>1;
    			printf("? %d ",v[mid].size());
    			for(int i=0;i<v[mid].size();i++)
    				print(v[mid][i]),putchar(' ');
    			putchar('\n');fflush(stdout);
     			int x,d;scanf("%d%d",&x,&d);
    			if(d==L)l=mid+1,u=x;
    			else r=mid-1;
    		}
    		v[L].clear();dfs(u,0,0);
    		printf("? %d ",v[L].size());
    		for(int i=0;i<v[L].size();i++)
    			print(v[L][i]),putchar(' ');
    		putchar('\n');fflush(stdout);
    		scanf("%d%d",&uu,&L);
    		printf("! %d %d\n",u,uu);fflush(stdout);
    		scanf("%s",s+1);
    	}
    }
    
  • 相关阅读:
    hdu 4496 D-City 并查集
    hdu 1257 小希的迷宫 并查集
    HDU 3974 Assign the task 图论/线段树区间更新,单点查询
    cdoj 1070 秋实大哥打游戏 带权并查集
    NumPy 广播(Broadcast)
    NumPy 高级索引
    NumPy 切片和索引
    NumPy 从数值范围创建数组
    Wasserstein距离
    JS散度
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14605585.html
Copyright © 2020-2023  润新知