#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=20010;
const int M=202000;
const int INF=0x7fffffff;
struct edge{
int u,v,next;
int id;
}edge[M];
int group[M],mmin[M];
int cnt,head[N];
int belong[M];
void addedge(int u,int v,int ii){
edge[cnt].u=u;edge[cnt].v=v;edge[cnt].next=head[u];
edge[cnt].id=ii;head[u]=cnt++;
edge[cnt].u=v;edge[cnt].v=u;edge[cnt].next=head[v];
edge[cnt].id=ii;head[v]=cnt++;
}
void init(int m){
cnt=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++){
mmin[i]=INF;
}
}
struct Tarjan{//求点双连通分量模板
int col;int top,index;//col表示染色,id标记dfn,top为栈顶指针
int dfn[N],low[N],temp[M];
int Stack[M];
void init(){
memset(dfn, 0, sizeof(dfn));
memset(group,-1,sizeof(group));
top=0;col=0;index=0;
}
void tarjan(int u,int pre){
//初始化dfn[u]和low[u];
dfn[u]=low[u]=++index;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(group[edge[i].id]!=-1)continue;
//节点v未被访问,则(u,v)为树边
if(!dfn[v]){
Stack[top++]=edge[i].id;//边进栈
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])//子节点不可能到比u更早的节点,u是割点
{
++col;
int k=edge[i].id;
int minn=INF;
do{
k=Stack[--top];
group[k]=col;
if(k<minn)minn=k;
}while(k!=edge[i].id);
mmin[col]=minn;
}
}
else {
if(v!=pre){//回边
Stack[top++]=edge[i].id;
low[u]=min(low[u],dfn[v]);
}
}
}
}
};
Tarjan tj;
int main(){
int n,m;
scanf("%d%d",&n,&m);
int u,v;
init(m);
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
addedge(u,v,i);
}
tj.init();
tj.tarjan(1,-1);
printf("%d\n",tj.col);
for(int i=1;i<=m;i++){
int aa=group[i];
printf("%d ",mmin[aa]);
}
printf("\n");
return 0;
}
hiho一下 第五十五周 连通性·四(无向图点双连通分量)
最新推荐文章于 2022-04-17 16:32:22 发布