https://atcoder.jp/contests/hitachi2020/tasks/hitachi2020_c
题目
某人很无聊,想给树上N个节点的每一个节点填一个1~N中的一个数。满足
- 所有填的数字都不同
- 距离为3的两个节点的两个数要么和是3的倍数,要么积是3的倍数
$2leqslant Nleqslant 2 imes 10^5$
题解
其实我不会,这是个构造题……
记一下之前的思路:
树上的点可以用距离为3的倍数这个等价关系分成3个商集 然后对3个树涂色,然后一顿乱涂,发现规约到NPC问题上去了……
把数字按照mod 3分成3类:A,B,C
相邻两个节点的颜色可以是A-B,A-C,B-C,C-C

C可以用来代替A或B,那么用A涂白色,B涂黑色,多余的部分用C涂
有个例外:$A+C$还不够涂白色,这时$B$肯定大于黑色的数量,因为A,B,C相差不超过1,因此等价于C大于等于黑色,用C涂黑色,剩下的随便涂
总结一下:
如果C大于等于黑色,那么用C涂黑色,剩下的随便涂
如果C大于等于白色,那么用C涂白色,剩下的随便涂
否则这时候A小于等于白色,B小于等于黑色,A涂白色,B涂黑色,不够的用C涂
这样就解决了1棵树的相邻节点的问题,距离为3可以拆成3个树,然后就解不出来了……
其实仍然可以用相邻节点,距离为3肯定保证不会出现A-A或B-B,这样就保证一定能构造出来
[egin{pmatrix}0 & 1 \ 1 & 0 end{pmatrix}^3=egin{pmatrix}0 & 1\1&0end{pmatrix} ]
AC代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define REP(i,a,b) for(register int i=(a); i<(b); i++)
#define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
#define PERE(i,a,b) for(register int i=(a); i>=(b); i--)
using namespace std;
typedef long long ll;
#define MAXN 200007
int hd[MAXN<<1], nxt[MAXN<<1], to[MAXN<<1], m=0;
inline void adde(int a, int b) {
nxt[m]=hd[a]; hd[a]=m; to[m]=b; m++;
}
int q[MAXN], c[MAXN], ans[MAXN], vis[MAXN];
int use[3]={1,2,3};
int n;
int go(int v) {
if(use[v]>n) {
int r=use[2];
use[2]+=3;
return r;
}
int r=use[v];
use[v]+=3;
return r;
}
inline void bfs1() {
int f=0, r=0;
memset(vis,0,sizeof vis);
ans[0]=0, ans[1]=0;
q[f++]=1; c[1]=0; vis[1]=1; ans[0]++;
while(r<f) {
int n=q[r], s=c[n]^1; r++;
for(int i=hd[n]; ~i; i=nxt[i]) {
int t=to[i];
if(!vis[t]) {
vis[t]=1;
c[t]=s;
ans[s]++;
q[f++]=t;
}
}
}
}
int main() {
memset(hd,-1,sizeof hd);
scanf("%d", &n);
REP(i,0,n) {
int a,b; scanf("%d%d", &a, &b);
adde(a,b); adde(b,a);
}
bfs1();
if(ans[0]<=n/3) {
int now=1, c2=3;
REPE(i,1,n) {
if(c[i]==0) {ans[i]=c2;c2+=3;}
}
REPE(i,1,n) {
if(c[i]==1) {
if(now%3==0 && now<c2) now++;
ans[i]=now;
now++;
}
}
} else if(ans[1]<=n/3) {
int now=1, c2=3;
REPE(i,1,n) {
if(c[i]==1) {ans[i]=c2;c2+=3;}
}
REPE(i,1,n) {
if(c[i]==0) {
if(now%3==0 && now<c2) now++;
ans[i]=now;
now++;
}
}
} else {
REPE(i,1,n) {
ans[i]=go(c[i]);
}
}
REPE(i,1,n) { if(i>1)putchar(' ');
printf("%d", ans[i]);
}
}