Link
对图进行二分图染色(染为红蓝色),那么可以得到一个结论,所有距离为3的节点的颜色都必不相同。
设\(R\)为红色节点的个数,\(B\)为蓝色节点的个数,\(X=\lfloor \frac N 3\rfloor\)。(这里假设\(R\leq B\))
将 1~n 分类为\(1\pmod 3,2\pmod 3,0\pmod3\)这三类,则有以下两种情况。
情况1:\(R\leq X\)
此时可以将所有红节点分配得到\(0\pmod 3\)的节点,这样每一个合法对\((i,j)\)(即\((i,j)\)的距离为3)都会有一个端点是3的倍数,它们的乘积必然是3的倍数。
情况2:\(R>X\)
此时将红节点分配得到\(1\pmod 3\)的节点,将蓝节点分配得到\(2\pmod 3\)的节点。剩下的\(0\pmod 3\)的节点随意分配。
这样每个合法对\((i,j)\)的端点要么有3的倍数,要么其和为3的倍数。
所以我们也证明了合法的排列分配方案是一定存在的。
#include
using namespace std;
typedef long long ll;
const int N = 200010;
int n;
vector G[N], v[2];
int p[N];
void dfs(int u, int fa, bool f) {
v[f].push_back(u);
for(auto &i : G[u]) if(i != fa) dfs(i, u, f ^ 1);
}
int main() {
scanf("%d", &n);
for(int u, v, i = 1; i < n; ++i) {
scanf("%d%d", &u, &v);
G[v].push_back(u);
G[u].push_back(v);
}
dfs(1, 1, 1);
if(v[0].size() > v[1].size()) swap(v[0], v[1]);
int x = n / 3;
if((int)v[0].size() <= x) {
int now = 3, T = 0;
for(auto &i : v[0]) p[i] = now, now += 3;
for(auto &i : v[1]) {
if(now > n) now = ++T;
p[i] = now;
now += 3;
}
} else {
int now = 1;
for(auto &i : v[0]) {
p[i] = now;
now += 3;
if(now > n) now = 3;
}
int T = now;
now = 2;
for(auto &i : v[1]) {
p[i] = now;
now += 3;
if(now > n) now = T;
}
}
for(int i = 1; i <= n; ++i) printf("%d ", p[i]);
return 0;
}