题意:
给出一幅n个点m条边的连通图 求图中有几个点双连通分量
并输出每条边所在点双连通分量中所有边的编号最小边的编号
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 20050
#define maxm 200050
using namespace std;
struct node{
int id,to,next;
}edge[maxm];
int head[maxn];
int s;
int num,dfn[maxn],low[maxn];
int sta[maxm],top;
int belong[maxm],temp[maxm],block,vis[maxn*5];
void Tarjan(int u,int pre)
{
dfn[u]=low[u]=++num;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(vis[edge[i].id]) //已标记的边不能通过同一条边的反向边再次访问
continue;
if(!dfn[v])
{
sta[top++]=edge[i].id; //边入栈
Tarjan(v,u);
low[u]=min(low[v],low[u]);
if(dfn[u]<=low[v])
{
block++;
int d=-1,s=0,minn=maxm;
while(d!=edge[i].id)
{
d=sta[--top];
temp[s++]=d;
vis[d]=1; //标记边
if(d<minn)
minn=d;
}
for(int i=0;i<s;i++)
belong[temp[i]]=minn;
}
}
else if(v!=pre){
sta[top++]=edge[i].id; //边入栈
low[u]=min(dfn[v],low[u]);
}
}
}
void init()
{
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(belong,0,sizeof(belong));
s=top=num=block=0;
}
int main()
{
// freopen("in.txt","r",stdin);
int n,m,a,b;
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
edge[s]={i,b,head[a]};
head[a]=s++;
edge[s]={i,a,head[b]};
head[b]=s++;
}
Tarjan(1,-1);
printf("%d\n",block);
for(int i=1;i<=m;i++)
printf("%d ",belong[i]);
cout<<endl;
return 0;
}