//求无向图:e-dcc(边双联通分量)
//重边的处理 e---e反
//low[x]>dfn[y],edge(x,y)才可以
//键图:belong[point]=edcc
struct node
{
int fr,to,nxt;
}e[N<<1];
int tot=1,head[N];
inline void add(int x,int y)
{
e[++tot].to=y,e[tot].nxt=head[x],head[x]=tot;
e[tot].fr=x;
}
int n,m;
int dfn[N],dfn_cnt,belong[N],low[N],edcc;
bool cut[N<<1];
inline void tarjan(int x,int lst_edge)
{
dfn[x]=low[x]=++dfn_cnt;
for(int i=head[x];i;i=e[i].nxt)
{
int to=e[i].to;
if(!dfn[to])
{
tarjan(to,i);
low[x]=min(low[x],low[to]);
if(low[to]>dfn[x])
{
cut[i]=cut[i^1]=1;
}
}
else if(i!=(lst_edge^1))low[x]=min(low[x],dfn[to]);
}
}
inline void dfs(int x)
{
belong[x]=edcc;
for(int i=head[x];i;i=e[i].nxt)
{
int to=e[i].to;
if(cut[i]||belong[to])continue;
//这里belong!=0就不行,因为我只是要找哪个点是哪个edcc,访问过了就没有必要访问了
dfs(to);
}
}
int main()
{
// freopen("exam.txt","r",stdin);
// freopen("a.out","w",stdout);
n=re(),m=re();
_f(i,1,m)
{
int u=re(),v=re();
add(u,v);add(v,u);
}
_f(i,1,n)if(!dfn[i])tarjan(i);
_f(i,1,n)
{
if(!belong[i])edcc++,dfs(i);
}//找出那个点属于哪些edcc
_f(i,2,tot)
{
if(belong[e[i].fr]!=belong[e[i].to])Add(e[i].fr,e[i].to);//这就是新的图了
}
return 0;
}
//求无向图:-dcc(点双联通分量)
//根节点必2个special point (o--o) dcc,x要留着 只要有,就放
//low[y]>=dfn[x]
//我每次判断找dcc时都是截止到这个儿子,所以每次tarjan一个儿子都要找一遍dcc
//如果有自环的话记得去掉否则单点算不上
struct node
{
int fr,to,nxt;
}e[N<<1];
int tot=1,head[N];
inline void add(int x,int y)
{
e[++tot].to=y,e[tot].nxt=head[x],head[x]=tot;
e[tot].fr=x;
}
int n,m;
int dfn[N],dfn_cnt,belong[N],low[N],edcc;
vector<int>dcc[N];
int cnt;bool cut[N];
int stack[N],top;
int root;
void tarjan(int x)
{
dfn[x]=low[x]=++dfn_cnt;
stack[++top]=x;
if(x==root&&head[x]==0)
{
dcc[++cnt].push_back(x);return ;
}
int f=0;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x])
{
f++;
if(f>1||x!=root)cut[x]=true;
cnt++;
int z=0;
do
{
z=stack[top--];
dcc[cnt].push_back(z);
}while(z!=y);
dcc[cnt].push_back(x);//但是x还要留在stack里面
}
}
else low[x]=min(low[x],dfn[y]);
}
}int num;
int main()
{
// freopen("exam.txt","r",stdin);
// freopen("a.out","w",stdout);
n=re(),m=re();
_f(i,1,m)
{
int u=re(),v=re();
add(u,v);add(v,u);
}
_f(i,1,n)if(!dfn[i])root=i,tarjan(i);
num=cnt;
for(int i=1;i<=cnt;i++)
{
if(cut[i])new_id[i]=++num;
}
tc=1;
for(int i=1;i<=cnt;i++)
{
for(int j=0;j<dcc[i].size();j++)
{
int x=dcc[i][j];
if(cut[x])
{
add_c(i,new_id[x]);
add_c[new_id[x],i);
}
else c[x]=i;
}
}
return 0;
}
//求有向图:-(强双联通分量)
//在求scc时我要遍历完x的所有子节点之后才能找,因为这
//不是单独的一个环,试想所有环都套在一块那也是scc
//low[y]==dfn[x],必须是仍然在队里面
struct node
{
int fr,to,nxt;
}e[N<<1];
int tot=1,head[N];
inline void add(int x,int y)
{
e[++tot].to=y,e[tot].nxt=head[x],head[x]=tot;
e[tot].fr=x;
}
int dfn[N],dfn_cnt,low[N];
int stack[N],top;
bool in[N];
vector<int>scc[N];
int cnt;
inline void tarjan(int x)
{
dfn[x]=low[x]=++dfn_cnt;
stack[++top]=x;
for(int i=head[x];i;i=e[i].nxt)
{
int to=e[i].to;
if(!dfn[to])
{
tarjan(to);
low[x]=min(low[x],low[to]);
}
else if(in[to])low[x]=min(dfn[to],low[x]);
}
if(dfn[x]==low[x])
{
cnt++;
int y;
do
{
y=stack[top--];
scc[cnt].push_back(y);ins[y]=0;c[y]=cnt;
}while(y!=x)
}
}
int main()
{
// freopen("exam.txt","r",stdin);
// freopen("a.out","w",stdout);
n=re(),m=re();
for(int i=1;i<=m;i++)
{
int x=re(),y=re();add(x,y);
}
_f(i,1,n)if(!dfn[i])tarjan(i);
_f(i,2,tot)
{
if(c[e[i].fr]==c[e[i].to])continue;
Add(e[i].fr,e[i].to);
}
return 0;
}