传送门
题意:给一棵nnn个结点的树,构造一个nnn阶排列ppp,使得所有距离为333的点对(i,j)(i,j)(i,j)满足pi+pjp_i+p_jpi+pj和pipjp_ip_jpipj至少一个为333的倍数。
分析一下,这个条件等价于所有距离333的点对点权对三取模后不都为111且不都为222
换句话说,所有余数为111的点中不存在距离为333的,222一样。
因为要求距离为333,可以二分图染色,把余数相同的放在同一个颜色中。
问题转换成了:把⌊n+23⌋\lfloor\frac{n+2}3\rfloor⌊3n+2⌋个111和⌊n+13⌋\lfloor\frac{n+1}3\rfloor⌊3n+1⌋个222放入两个集合,要求相同的数只能放在同一个集合。且这两个集合最多分别只能放x,yx,yx,y个,其中x+y=nx+y=nx+y=n
如果x,yx,yx,y中一个很大,就把两个都放进去,否则分开放。
根据意识流一定可以放下,瞎搞一波即可。
最后剩下的放333
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 200005
#define MAXM 400005
using namespace std;
struct edge{int u,v;}e[MAXM];
int head[MAXN],nxt[MAXM],cnt;
void addnode(int u,int v)
{e[++cnt]=(edge){u,v};nxt[cnt]=head[u];head[u]=cnt;
}
int col[MAXN],tot[2],p[MAXN],n;
void dfs(int u)
{++tot[col[u]];for (int i=head[u];i;i=nxt[i])if (col[e[i].v]==-1)col[e[i].v]=col[u]^1,dfs(e[i].v);
}
inline void putp(int r,int c)//freedomly put r+3k into color c
{int cur=r;for (int i=1;i<=n;i++)if (col[i]==c&&!p[i]){p[i]=cur,cur+=3;if (cur>n) return;}
}
int main()
{scanf("%d",&n);for (int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);addnode(u,v),addnode(v,u);}memset(col,-1,sizeof(col));for (int i=1;i<=n;i++) if (col[i]==-1) col[i]=0,dfs(i);int k=(n+1)/3;if (k<=min(tot[0],tot[1])) putp(2,tot[1]<=tot[0]);else putp(2,tot[1]>tot[0]);putp(1,tot[1]>tot[0]);int cur=3;for (int i=1;i<=n;i++)if (!p[i])p[i]=cur,cur+=3;for (int i=1;i<=n;i++) printf("%d%c",p[i]," \n"[i==n]);return 0;
}