题目
题解
x ^ y <= min(x,y) 等价于x、y二进制最高位相同。只要树上每条边的邻点都满足该条件,那么先手无论将棋子放哪都必胜。考虑如何构造。
可以将树01染色,相邻点颜色不同, 将所有点分为两类,不同类的最高位都不同即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
vector<int> mp[N];
vector<int> vec[N];
vector<int> col[3];
int get(int x)
{
int res = 0;
while (x)
{
x /= 2;
res++;
}
return res;
}
void init(int n)
{
for (int i = 0; i <= 1; i++)
col[i].clear();
for (int i = 0; i <= 31; i++)
vec[i].clear();
for (int i = 1; i <= n; i++)
vec[get(i)].emplace_back(i), mp[i].clear();
}
int ans[N];
int n;
void dfs(int u, int fa, int COL)
{
col[COL].emplace_back(u);
for (auto v : mp[u])
{
if (v == fa)
continue;
dfs(v, u, COL ^ 1);
}
}
void solve()
{
scanf("%d", &n);
init(n);
for (int i = 1; i < n; i++)
{
int u, v;
scanf("%d %d", &u, &v);
mp[u].emplace_back(v);
mp[v].emplace_back(u);
}
dfs(1, -1, 0);
if (col[0].size() > col[1].size()) //取小的那一堆
swap(col[0], col[1]);
int L = 1, R = get(n);
int m = col[0].size();
for (int i = R; i >= 1; i--) //用若干种先凑成col[0]
{
int num = vec[i].size();
if (m >= num)
{
m -= num;
while (num--)
{
ans[col[0].back()] = vec[i].back();
col[0].pop_back();
vec[i].pop_back();
}
}
}
for (int i = R; i >= 1; i--) //剩下的全给col[1]
{
int num = vec[i].size();
while (num--)
{
ans[col[1].back()] = vec[i].back();
col[1].pop_back();
vec[i].pop_back();
}
}
for (int i = 1; i <= n; i++)
printf("%d ", ans[i]);
puts("");
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
solve();
return 0;
}