无向图的双连通分量
/****************** 割点 割边 ******************/
struct EBCC
{
int head[N], edge[N << 1], Next[N << 1], tot;
int dfn[N], low[N], n, m, num = 0, root = 0;
bool cut[N], bridge[N << 1];
// 调用前先初始化
void init()
{
for (int i = 0; i < N; i ++ )
{
head[i] = edge[i] = Next[i] = dfn[i] = low[i] = cut[i] = bridge[i] = 0;
}
}
// 建边
void add_edge(int a, int b)
{
edge[++tot] = b;
Next[tot] = head[a];
head[a] = tot;
}
// 割点
void Tarjan1(int x)
{
dfn[x] = low[x] = ++num;
int flag = 0;
for (int i = head[x]; i; i = Next[i])
{
int y = edge[i];
if (!dfn[y])
{
Tarjan1(y);
low[x] = min(low[x], low[y]);
if (low[y] >= dfn[x])
{
flag++;
if (x != root || flag > 1) cut[x] = true;
}
}
else low[x] = min(low[x], dfn[y]);
}
}
// 割边/桥
void Tarjan2(int x, int Edge)
{
dfn[x] = low[x] = ++num;
for (int i = head[x]; i; i = Next[i])
{
int y = edge[i];
if (!dfn[y])
{
Tarjan2(y, i);
low[x] = min(low[x], low[y]);
if (low[y] > dfn[x]) bridge[i] = bridge[i ^ 1] = true;
}
else if (i != (Edge ^ 1)) low[x] = min(low[x], dfn[y]);
}
}
// 调用此函数求割点 调用后cut[u]表示u是否为割点
void work1()
{
for (int i = 1; i <= n; i ++ )
{
if (!dfn[i])
{
root = i;
Tarjan1(i);
}
}
}
// 调用此函数求桥 调用后bridge[e]表示边e是否为桥
void work2()
{
for (int i = 1; i <= n; i ++ )
{
if (!dfn[i]) Tarjan2(i, 0);
}
}
/* 下方填写解题逻辑 */
void solve()
{
init();
cin >> n >> m;
for (int i = 0; i < m; i ++ )
{
int u, v; cin >> u >> v;
add_edge(u, v);
add_edge(v, u);
}
work1();
vector<int> ans;
for (int i = 1; i <= n; i ++ )
{
if (cut[i]) ans.push_back(i);
}
cout << ans.size() << '\n';
for (auto t : ans) cout << t << ' ';
}
} ebcc;
/***********************************************/