>Link
luogu T207969
>Description
n
≤
500
n \le 500
n≤500
idea:stoorz
>解题思路
本人写的第一道交互题QwQ
我们假定 1 为根,那就可以通过
n
−
1
n-1
n−1 次询问第
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;
}