struct Tarjan
{
int dfn[maxn], low[maxn], Time;
bool vis_cutnode[maxn], vis_bridge[maxn];
combo Tarjan_gd(int u, int fa)
{//有/无 向图的割点
dfn[u] = low[u] = ++ Time;
int cnt = 0;
for (int i = heade[u]; i; i = e[i].next)
{
int v = e[i].to;
if(! dfn[v])
{
Tarjan_gd(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u])
{
cnt ++;
if(fa != 0 || cnt > 1)
{
vis_cutnode[u] = true;
}
}
else
{
low[u] = min(low[u], dfn[v]);
}
}
}
return;
}
combo Tarjan_gb(int u, int id_edge)
{//有/无 向图的割边
dfn[u] = low[u] = ++ Time;
for (int i = heade[u]; i; i = e[i].next)
{
int v = e[i].to;
if(i == id_edge ^ 1) continue;
if(! dfn[v])
{
Tarjan_gb(v, i);
low[u] = min(low[u], low[v]);
if(low[v] > dfn[u])
{
vis_bridge[i] = vis_bridge[i ^ 1] = true;
}
}
else
{
low[u] = min(low[u], dfn[v]);
}
}
return;
}
//SD//缩点 (有向图)
int st[maxn], top, tot_s;
int belong[maxn];
combo Tarjan_sd(int u)//缩点 (有向图)
{
dfn[u] = low[u] = ++ Time;
st[++ top] = u;
for (int i = heade[u]; i; i = e[i].next)
{
int v = e[i].to;
if(!dfn[v])
{
Tarjan_sd(v);
low[u] = min(low[u], low[v]);
}
else
{
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u])
{
tot_s ++;
while(st[top + 1] != u)
{
belong[st[top --]] = tot_s;
}
}
return;
}
//v_DCC//点双联通分量 (无向图)
int num, tot_v;
int new_id[maxn]\;
vector <int> v_dcc[maxn];
combo Tarjan_ds(int u, int fa)
{//无向图的点双联通分量 v_DCC
dfn[u] = low[u] = ++ Time;
st[++ top] = u;
if(fa == 0 && heade[u] == 0)
{
v_dcc[++ tot_v].push_back(u);
return;
}
int cnt = 0;
for (int i = heade[u]; i; i = e[i].next)
{
int v = e[i].to;
if(! dfn[v])
{
Tarjan_ds(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u])
{
cnt ++;
if(fa != 0 || cnt > 0) vis_cutnode[u] = true;
while(st[top + 1] != v)
{
v_dcc[++ tot_v].push_back(st[top --]);
}
}
}
else
{
low[u] = min(low[u], dfn[v]);
}
}
return;
}
combo get_ds_sd()
{
num = tot_v;
for (int i = 1; i <= n; ++ i)
{
if(vis_cutnode[i])
{
new_id[i] = ++ num;
}
}
for (int i = 1; i <= tot_v; ++ i)
{
for (int j = 0; j < v_dcc[i].size(); ++ j)
{
int u = v_dcc[i][j];
if(vis_cutnode[u])
{
Insertg(i, new_id[u]), Insertg(new_id[u], i);
}
else
{
belong[u] = i;
}
}
}
return;
}
//e_DCC//边双联通分量 (无向图)
int e_DCC[maxn], tot_e;
combo Dfs_e_DCC(int u)
{
e_DCC[u] = tot_e;
for (int i = heade[u]; i; i = e[i].next)
{
int v = e[i].to;
if(e_DCC[v] || vis_bridge[i]) continue;
Dfs_e_DCC(v);
}
}
combo get_bs()
{//无向图的边双联通分量 e_DCC
for (int i = 1; i <= n; ++ i)
{
if(!e_DCC[i])
{
++ tot_e; Dfs_e_DCC(i);
}
}
return;
}
combo get_bs_sd()
{//边双联通分量的缩点
for (int i = 2; i <= tote; ++ i)
{
int u = e[i ^ 1].to, v = e[i].to;
if(e_DCC[u] == e_DCC[v]) continue;
Insertg(u, v);
}
}
}T;