AT_hitachi2020_c ThREE 题解
题意:给定一颗树,构造一个排列 \(p\) 使得对于每一对 \((x,y),dis(x,y)=3\),有 \(3 \mid p_x+p_y\) 或 \(3 \mid p_x \times p_y\)。
首先我们先将所有 \(p_i\) 都模上 \(3\)。
条件等价于每一对距离为 \(3\) 的 \((x,y)\),\(p_x\) 和 \(p_y\) 不同时为 \(1\) 或 \(2\)。
那先考虑如何填 \(1\),题意转化为将一些点涂黑,没有两个黑点的距离为 \(3\)。
会发现若所有的黑点的深度的奇偶性都相同,那么不可能有两个点的距离为奇数。所以构造方案为:把这些黑点全部填到深度为偶数的点上或者全部填到深度为奇数的点上。具体填偶还是奇取决于哪边的点数够。
填 \(2\) 的情况同理,\(0\) 就是剩下所有没被填的点。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 2e5 + 10;
int n,head[MAXN],cnt,depth[MAXN],ans[MAXN],p[5] = {3,1,2,0,0};
vector <int> v[3];
struct Node {int u,v,nxt;}e[MAXN << 1];
inline void Add(int u,int v) {e[++cnt] = {u,v,head[u]};head[u] = cnt;}
inline void dfs(int u,int father) {
depth[u] = depth[father] + 1,v[depth[u] % 2].emplace_back(u);
for(int i = head[u]; ~ i;i = e[i].nxt)
if(e[i].v != father) dfs(e[i].v,u);
} signed main() {
memset(head,-1,sizeof head); cin >> n;
for(int i = 1,x,y;i < n;i++)
cin >> x >> y,Add(x,y),Add(y,x);
dfs(1,0);
int sum1 = n / 3 + (n % 3 == 1 || n % 3 == 2);
int sum2 = n / 3 + (n % 3 == 2);
int size0 = v[0].size(),size1 = v[1].size();
if(size0 >= sum1) {
for(int i = size0 - sum1;i < size0;i++) ans[v[0][i]] = 1;
size0 -= sum1;
} else {
for(int i = size1 - sum1;i < size1;i++) ans[v[1][i]] = 1;
size1 -= sum1;
} if(size0 >= sum2) for(int i = 0;i < sum2;i++) ans[v[0][i]] = 2;
else for(int i = 0;i < sum2;i++) ans[v[1][i]] = 2;
for(int i = 1;i <= n;i++)
cout << p[ans[i]] << " ",p[ans[i]] += 3;
return 0;
}