强连通分量 tarjan
struct scc{
const int nn;
int cnt,idx;
vector<int> col,dfn,low,stk;
vector<bool> onstk;
vector<vector<int>> g,comp;
scc(int n1):nn(n1),cnt(0),idx(0),col(n1),dfn(n1,0),low(n1),stk(n1),onstk(n1,0),g(n1){}
void add_edge(int u,int v)
{
g[u].push_back(v);
}
void dfs(int u)
{
dfn[u]=low[u]=++cnt;
stk.push_back(u);
onstk[u]=true;
for(auto v:g[u])
{
if(!dfn[v])
dfs(v);
if(onstk[v])
low[u]=min(low[u],low[v]);
}
if(low[u]==dfn[u])
{
comp.emplace_back();
while(true)
{
int v=stk.back();
stk.pop_back();
onstk[v]=false;
comp.back().push_back(v);
if(u==v)
break;
}
}
}
void solve()
{
for(int i=0;i<nn;i++)
if(!dfn[i])
dfs(i);
int sz=comp.size();
// reverse(comp.begin(), comp.end()); to sort components in topological
// order
for(int i=0;i<(int)comp.size();i++)
for(int x:comp[i])
col[x]=i;
}
};
割点和桥tarjan
struct Tarjan{
const int nn;
int cnt;
vector<int> dfn,low,bridges,point;
vector<vector<pair<int,int> > > g;
Tarjan(int n1):nn(n1),cnt(0),dfn(n1,0),low(n1),point(n1,0),g(n1){}
void add_edge(int u,int v,int i)
{
g[u].emplace_back(v,i);
g[v].emplace_back(u,i);
}
void dfs(int u,int fr)
{
dfn[u]=low[u]=++cnt;
int child=0,time=0;
for(auto [v,i]:g[u])
{
if(v==fr&&time==0)
{
time++;
continue;
}
if(!dfn[v])
{
child++;
dfs(v,u);
if(u==fr&&child>=2)
point[u]=1;
if(u!=fr&&low[v]>=dfn[u]&&child>=1)
point[u]=1;
low[u]=min(low[u],low[v]);
}
if(fr!=v)
low[u]=min(low[u],dfn[v]);
if(low[v]>dfn[u])
bridges.push_back(i);
}
}
void solve()
{
for(int i=0;i<nn;i++)
if(!dfn[i])
dfs(i,i);
cout<<count(point.begin(),point.end(),1)<<endl;
for(int i=0;i<nn;i++)
{
if(point[i])
cout<<i+1<<" ";
}
cout<<endl;
for(auto x:bridges)
cout<<x<<" ";
}
};