struct EDCC
{
int n, now, cnt;
vector<vector<int>> ver;
vector<int> dfn, low, col, S;
set<array<int, 2>> bridge;
EDCC(int n) : n(n), ver(n + 1), low(n + 1)
{
dfn.resize(n + 1, -1);
col.resize(n + 1, -1);
now = cnt = 0;
}
void add(int x, int y)
{
ver[x].push_back(y);
ver[y].push_back(x);
}
void tarjan(int x, int fa)
{
dfn[x] = low[x] = now++;
S.push_back(x);
for (auto y : ver[x])
{
if (y == fa)
continue;
if (dfn[y] == -1)
{
bridge.insert({x, y});
tarjan(y, x);
low[x] = min(low[x], low[y]);
}
else if (col[y] == -1 && dfn[y] < dfn[x])
{
bridge.insert({x, y});
low[x] = min(low[x], dfn[y]);
}
}
if (dfn[x] == low[x])
{
int pre;
cnt++;
do
{
pre = S.back();
col[pre] = cnt;
S.pop_back();
} while (pre != x);
}
}
auto work()
{ // [cnt 新图的顶点数量, bridge 全部割边]
for (int i = 1; i <= n; i++) // 避免图不连通
if (dfn[i] == -1)
tarjan(i, 0);
vector<int> siz(cnt + 1); // siz 每个边双中点的数量
vector<vector<int>> adj(cnt + 1); // adj 新图
for (int i = 1; i <= n; i++)
{
siz[col[i]]++;
for (auto j : ver[i])
{
int x = col[i], y = col[j];
if (x != y)
adj[x].push_back(y);
}
}
return tuple{cnt, adj, col, siz};
}
};