link
sol
这个问题显然只有 \(\%3\) 的余数才有用,所以我们用 \(i \% 3\) 来替换 \(i\)
很容易发现,只要点对中存在一个 \(0\) ,那么肯定满足条件,所以先使用 \(1\) 和 \(2\) 来构造
要使得一个距离为 \(3\) 的点对符合要求,那么必须要让一个为 \(1\) ,一个为 \(2\),所以要使得所有权值相同的点不为 \(3\)。
由于 \(3\) 是单数,所以我们想到将树黑白染色,每一个点都与它相连的点颜色不同,所以将 黑白分别分配给 \(1,2\)
然后考虑加入 \(0\) 的情况
我们先默认 黑点数 \(≤\) 白点数
然后分两种情况
- 黑点数 \(≤ {n\over 3}\)
此时要将 \(0\) 来填充黑点,因为只要点对中出现一个 \(0\) 就必然合法,然后将 \(1,2\) 和剩下的 \(0\) 加入白点
- 黑点数 \(>{n\over 3}\) 可以先把 \(1,2\) 插入黑点,白点,然后将 \(0\) 填入剩下的黑点白点
code
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
vector<int> v[3],c[3];
int N;
vector<int> e[200005];
int P[200005],col[200005];
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
void dfs(int x,int fa){
col[x]=1-col[fa];
c[col[x]+1].push_back(x);
for(auto i:e[x]) if(i^fa) dfs(i,x);
}
int main(){
freopen("AT5759.in","r",stdin);
freopen("AT5759.out","w",stdout);
N=read();
for(int i=1,x,y;i<N;i++){
x=read(),y=read();
e[x].push_back(y);e[y].push_back(x);
}
dfs(1,0);
for(int i=1;i<=N;i++) v[i%3].push_back(i);
if(c[1].size()>c[2].size())swap(c[2],c[1]);
int cnt0=0,cnt1=0,cnt2=0;
if(c[1].size()<=N/3){
for(auto i:c[1]) P[i]=v[0][cnt0++];
for(auto i:c[2]){
if(cnt0<v[0].size())P[i]=v[0][cnt0++];
else if(cnt1<v[1].size())P[i]=v[1][cnt1++];
else if(cnt2<v[2].size())P[i]=v[2][cnt2++];
}
}
else {
for(auto i:c[1]){
if(cnt1<v[1].size())P[i]=v[1][cnt1++];
else P[i]=v[0][cnt0++];
}
for(auto i:c[2]){
if(cnt2<v[2].size())P[i]=v[2][cnt2++];
else P[i]=v[0][cnt0++];
}
}
for(int i=1;i<=N;i++)printf("%d ",P[i]);
return 0;
}