//割边
int dfn[MAXN], low[MAXN], idx;
bool bridge[MAXN];
void tarjan(int now, int f)
{
dfn[now] = low[now] = ++idx;
for (int i = head[now]; i; i = nxt[i])
{
if(v[i] == f) continue;
if(!dfn[v[i]])
{
tarjan(v[i], now);
low[now] = min(low[now], low[v[i]]);
if(low[v[i]] > dfn[now]) bridge[i] = bridge[i ^ 1] = 1;//成对变换,记录割边
}
else
{
low[now] = min(low[now], v[i]);
}
}
}
//割点 考虑根节点作为割点的情况
int root, flag;//根,记录有几个根的子节点满足,要至少两个以上
int dfn[MAXN], low[MAXN], idx;
bool cut[MAXN];
void tarjan(int now, int f)
{
dfn[now] = low[now] = ++idx;
for (int i = head[now]; i; i = nxt[i])
{
if(v[i] == f) continue;
if(!dfn[v[i]])
{
tarjan(v[i], now);
low[now] = min(low[now], low[v[i]]);
if(low[v[i]] >= dfn[now])
{
if(now == root) flag++;
if(now != root || flag > 1) cut[now] = 1;
}
}
else
{
low[now] = min(low[now], v[i]);
}
}
}
//e-DCC 边双连通分量
int e_dcc[MAXN], inddcc;
int hdc[MAXN], vdc[MAXN], ndc[MAXN], cntdc = 1;
int c[MAXN];
void adddc(int x, int y)
{
ndc[++cntdc] = hdc[x]; hdc[x] = cntdc; vdc[cntdc] = y;
}
void dfs(int now)
{
c[now] = inddcc;
for (int i = head[now]; i; i = nxt[i])
{
if(c[v[i]] || bridge[i]) continue;
dfs(v[i]);
}
}
for (int i = 1; i <= n; i++)
{
if(!c[i]) ++inddcc, dfs(i);
}
for (int i = 2; i <= tot; i++)
{
int x = vdc[i], y = vdc[i ^ 1];
if(c[x] ^ c[y]) adddc(c[x], c[y]);
}
//v-DCC 点双连通分量
vector<int> dcc[MAXN], inddcc;
int hdc[MAXN], vdc[MAXN], ndc[MAXN], cntdc = 1;
int root, flag;
int dfn[MAXN], low[MAXN], idx;
bool cut[MAXN];
int stac[MAXN], top = 1;
int c[MANX], new_id[MAXN], tot;
void tarjan(int now, int f)
{
dfn[now] = low[now] = ++idx;
stac[top++] = now;
if(now == root && head[now] == 0)
{
dcc[++inddcc].push_back(now);
return;
}
for (int i = head[now]; i; i = nxt[i])
{
if(v[i] == f) continue;
if(!dfn[v[i]])
{
tarjan(v[i], now);
low[now] = min(low[now], low[v[i]]);
if(low[v[i]] >= dfn[now])
{
if(now == root) flag++;
if(now != root || flag > 1) cut[now] = 1;
++inddcc;
while(stac[top - 1] != v[i])
{
dcc[inddcc].push_back(stac[--top]);
}
dcc[inddcc].push_back(now);
}
}
else
{
low[now] = min(low[now], v[i]);
}
}
}
void adddc(int x, int y)
{
ndc[++cntdc] = hdc[x]; hdc[x] = cntdc; vdc[cntdc] = y;
}
tot = inddcc;
for (int i = 1; i <= n; i++)
{
if(cut[i]) new_id[i] = ++tot;
}
for (int i = 1; i <= inddcc; i++)
for (int j = 0; j < dcc[i].size(); j++)
{
if(cut[dcc[i][j]])
{
adddc(i, new_id[dcc[i][j]]);
adddc(new_id[dcc[i][j]], i);
}
else c[d[i][j]] = i;
}