CF830E Perpetual Motion Machine
先假设图是联通的。
如果
由于图联通,所以
于是我们只需要考虑
令
如果
如果
如果
剩下的情况就是
容易发现这种情况下树的形态一定是从
设
再设
那么我们就是要令
对于一条链上的连续
可以发现,如果固定
也就是说,对于
不妨在
于是可以得出
我们再尝试进行构造。
-
如果
|L_1|\ge 2 ,那么考虑|L_1|=|L_2|=|L_3|=2 ,d_u=3,c_1=c_2=c_3=1 即可。 -
如果
|L_1|=1 - 如果
|L_2|=1 ,那么无解。 - 如果
|L_2|\ge 3 ,那么考虑|L_1|=1,|L_2|=|L_3|=3 ,d_u=4,c_1=2,c_2=c_3=1 即可。 - 如果
|L_2|=2 - 如果
|L_3|\le 4 ,那么无解。 - 如果
|L_3|\ge 5 ,那么考虑|L_1|=1,|L_2|=2,|L_3|=5 ,d_u=6,c_1=3,c_2=2,c_3=1 即可。
- 如果
- 如果
综上,我们找到了图联通时的构造方法,正确性显然。
如果图不联通就对于每一个连通块做一遍。如果存在某一个连通块合法,那么就按照上述方法构造,并把其它连通块全部赋为
时间复杂度
参考代码:
#include <bits/stdc++.h>
using namespace std;
#define N 100005
#define pb push_back
int T,n,m,ps,nw,fa[N],fa1[N],lst[N],ans[N];vector<int> z[3],e[N];
int findRt(int u) {return u==fa[u]?u:fa[u]=findRt(fa[u]);}
bool merge(int u,int v)
{u=findRt(u);v=findRt(v);if(u==v) return 0;fa[u]=v;return 1;}
void dfs(int u,int f) {fa1[u]=f;for(auto v:e[u]) if(v!=f) dfs(v,u);}
void dfs1(int u,int f)
{
if(f) z[nw].pb(u);if(e[u].size()==1) ++nw;
for(auto v:e[u]) if(v!=f) dfs1(v,u);
}
void slv()
{
scanf("%d %d",&n,&m);ps=0;for(int i=1;i<=n;++i) fa[i]=i,e[i].clear();
for(int i=1,u,v;i<=m;++i)
{scanf("%d %d",&u,&v);e[u].pb(v);e[v].pb(u);if(!merge(u,v)) ps=u;}
if(ps)
{
puts("YES");
for(int i=1;i<=n;++i) printf("%d ",findRt(ps)==findRt(i));
puts("");return;
}ps=0;for(int i=1;i<=n;++i) if(e[i].size()>3) ps=i;
if(ps)
{
puts("YES");
for(int i=1;i<=n;++i) printf("%d ",ps==i?2:(findRt(ps)==findRt(i)));
puts("");return;
}for(int i=1;i<=n;++i) lst[i]=ans[i]=0;
for(int i=1,t;i<=n;++i) if(e[i].size()>2)
{
t=findRt(i);if(!lst[t]) {lst[t]=i;continue;}
dfs(i,0);for(int j=lst[t];j;j=fa1[j]) ans[j]=2;puts("YES");
for(int j=1;j<=n;++j) printf("%d ",ans[j]?2:(findRt(i)==findRt(j)));
puts("");return;
}
for(int i=1;i<=n;++i) if(e[i].size()>2)
{
nw=0;z[0].clear();z[1].clear();z[2].clear();dfs1(i,0);
if(z[0].size()>z[1].size()) swap(z[0],z[1]);
if(z[0].size()>z[2].size()) swap(z[0],z[2]);
if(z[1].size()>z[2].size()) swap(z[1],z[2]);
if(z[0].size()>1)
{
ans[i]=3;ans[z[0][0]]=ans[z[1][0]]=ans[z[2][0]]=2;
ans[z[0][1]]=ans[z[1][1]]=ans[z[2][1]]=1;
puts("YES");for(int j=1;j<=n;++j) printf("%d ",ans[j]);puts("");return;
}
if(z[1].size()>2)
{
ans[i]=4;ans[z[0][0]]=2;ans[z[1][0]]=ans[z[2][0]]=3;
ans[z[1][1]]=ans[z[2][1]]=2;ans[z[1][2]]=ans[z[2][2]]=1;
puts("YES");for(int j=1;j<=n;++j) printf("%d ",ans[j]);puts("");return;
}if(z[1].size()<2) continue;
if(z[2].size()>4)
{
ans[i]=6;ans[z[0][0]]=3;ans[z[1][0]]=4;ans[z[1][1]]=2;
ans[z[2][0]]=5;ans[z[2][1]]=4;ans[z[2][2]]=3;ans[z[2][3]]=2;ans[z[2][4]]=1;
puts("YES");for(int j=1;j<=n;++j) printf("%d ",ans[j]);puts("");return;
}
}puts("NO");
}
int main() {scanf("%d",&T);while(T--) slv();return 0;}