AT5759 ThREE
AT5759 ThREE
一道简单的贪心题.
题目给出一棵树, 边权为 \(1\) , 要将树上的点填上 \(1 \sim n\) , 使得距离为 \(3\) 的两个点上的数满足积和和至少有一个为 \(3\) 的倍数.
很简单, 我们先进行一下黑白染色, 那么距离为 \(3\) 的点的颜色一定不同, 接下来我们分类讨论:
设白点个数为 \(wht\) , 黑点个数为 \(blk\) , \(num1, num2, num3\) 分别代表 \(\mod 3 == 1, 2, 0\) 的数.
- 如果 \(wht\) 和 \(blk\) 中有一个 \(\le n / 3\) 那么我们直接把这个颜色的点全都赋成 \(3\) 的倍数, 这样其它的点不管怎么选都合法, 因为任意一对点中至少有一个 \(3\) 的倍数, 乘积合法.
- 如果 $wht \ge num1 $ 并且 $ blk \ge num2 $ , 说明我们的黑白点都多于 \(n / 3\) 也就是说只靠乘积我们已经无法造出合法方案了, 那就得利用上和了. 一个 \(\mod n == 1\) 的数和一个 \(\mod n == 2\) 的数的和是合法的. 所以我们就先将这两种数分别填入两种颜色的点, 然后 \(3\) 的倍数随便填.
\(code:\)
#include <bits/stdc++.h>
using namespace std;
int read() {
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
const int N = 2e5 + 5, M = 4e5 + 5;
int n, ans[N], num1, num2, num3;
int col[N], wht, blk;
int tot, to[M], nxt[M], head[N];
void add(int u, int v) {
to[++tot] = v, nxt[tot] = head[u], head[u] = tot;
}
void dfs(int x, int fa) {
for (int i = head[x]; i; i = nxt[i]) {
int y = to[i];
if (y == fa) continue;
col[y] = !col[x];
dfs(y, x);
}
}
void init() {
n = read();
for (int i = 1; i < n; i++) {
int u = read(), v = read();
add(u, v); add(v, u);
}
num1 = num2 = num3 = n / 3;
if (n % 3 == 1) num1++;
else if (n % 3 == 2) num1++, num2++;
dfs(1, 0);
for (int i = 1; i <= n; i++) {
if (col[i]) wht++;
else blk++;
}
}
void solve1() {
int now = 1;
for (int i = 1; i <= n && now <= n; i++) {
if (col[i]) ans[i] = now, now += 3;
}
now = 2;
for (int i = 1; i <= n && now <= n; i++) {
if (!col[i]) ans[i] = now, now += 3;
}
now = 3;
for (int i = 1; i <= n && now <= n; i++) {
if (!ans[i]) ans[i] = now, now += 3;
}
}
void solve2() {
int now = 3, opt = 1;
if (wht <= num3) opt = 0;
for (int i = 1; i <= n; i++) {
if (col[i] ^ opt) ans[i] = now, now += 3;
}
for (int i = 1; now <= n; i++) {
if (!ans[i]) ans[i] = now, now += 3;
}
now = 1;
for (int i = 1; now <= n; i++) {
if (!ans[i]) ans[i] = now, now += 3;
}
now = 2;
for (int i = 1; now <= n; i++) {
if (!ans[i]) ans[i] = now, now += 3;
}
}
int main() {
init();
if (wht >= num1 && blk >= num2) solve1();
else solve2();
for (int i = 1; i <= n; i++) printf("%d ", ans[i]);
printf("\n");
return 0;
}
看不见我看不见我看不见我