hitachi2020 C-ThREE

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;
}

你可能感兴趣的:(hitachi2020 C-ThREE)