hiho一下 第五十五周 连通性·四(无向图点双连通分量)

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值