Spasmodic(交互题)【树】【二分】

>Link

luogu T207969


>Description

在这里插入图片描述
n ≤ 500 n \le 500 n500

idea:stoorz


>解题思路

本人写的第一道交互题QwQ

我们假定 1 为根,那就可以通过 n − 1 n-1 n1 次询问第 i i i 个点和第 1 1 1 个点得到每个节点的深度,将图分层
现在我们要找到当前这层,每个点的父亲,显然这些父亲都是在上一层的
既然枚举到了这一层,那就说明前面的层的父子关系都是确定了的,我们可以处理出 g i g_i gi,表示上一层前 i i i 个点与根节点的最小连通子图的大小
二分当前节点的父亲是哪个,询问上一层 m i d mid mid 之前所有的点,和根节点、当前节点的最小连通子图大小,如果大小 = g m i d + 1 =g_{mid}+1 =gmid+1,可以得出结论当前节点的父亲在 m i d mid mid 之前,否则在之后


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 510
using namespace std;

struct node
{
    
    
	int dep, id;
} a[N];
int n, fa[N], g[N], x, last, L, R, l, r, mid;
bool vis[N];

bool cmp (node aa, node bb) {
    
    return aa.dep < bb.dep;}

int main()
{
    
    
	scanf ("%d", &n);
	a[1] = (node){
    
    0, 1};
	for (int i = 2; i <= n; i++)
	{
    
    
		std::cout << 1 << " " << 2 << " " << 1 << " " << i << std::endl;
		std::cout << std::flush;
		std::cin >> x;
		a[i] = (node){
    
    x, i};
	}
	sort (a + 1, a + 1 + n, cmp);
	L = R = last = 1;
	for (int i = 2; i <= n; i++)
	{
    
    
		if (a[i].dep != a[i - 1].dep)
		{
    
    
			memset (vis, 0, sizeof (vis));
			memset (g, 0, sizeof (g));
			for (int j = last; j <= i - 1; j++)
			{
    
    
				g[j] = g[j - 1];
				for (int now = a[j].id; now > 1; now = fa[now])
			      if (!vis[now]) vis[now] = 1, g[j]++;
				  else break;
			}
			L = last, R = i - 1, last = i;
		}
		l = L, r = R;
		while (l < r)
		{
    
    
			mid = (l + r) / 2;
			std::cout << 1 << " " << mid - L + 3;
			std::cout << " " << 1 << " " << a[i].id;
			for (int j = L; j <= mid; j++)
			  std::cout << " " << a[j].id;
			std::cout << std::endl;
			std::cout << std::flush;
			std::cin >> x;
			if (x == g[mid] + 1) r = mid;
			else l = mid + 1;
		}
		fa[a[i].id] = a[r].id;
	}
	std::cout << 2;
	for (int i = 2; i <= n; i++)
	  std::cout << " " << fa[i] << " " << i;
	std::cout << std::endl;
	std::cout << std::flush;
	return 0;
}

おすすめ

転載: blog.csdn.net/qq_43010386/article/details/121236238