点双连通分量
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
int n,m,t,ans;
int dfn[100001],low[100001],sum,in;
vector<int>gcc[100001],g[100001];
stack<int>s;
void tarjan(int u,int fa) {
dfn[u]=low[u]=++in;
if(fa==-1&&g[u].size()==0){
gcc[u].push_back(++sum);
return;
}
s.push(u);
for(int i=0; i<g[u].size(); i++) {
int v=g[u][i];
if(v==fa)continue;
if(!dfn[v]) {
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
sum++;
int d;
do{
d=s.top();
s.pop();
gcc[d].push_back(sum);
}while(d!=v);
gcc[u].push_back(sum);
}
} else {
low[u]=min(low[u],dfn[v]);
}
}
}
int main() {
cin>>n>>m;
while(m--) {
int x,y;
cin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}
for(int i=1; i<=n; i++) {
if(!dfn[i])tarjan(i,-1);
}
return 0;
}
边双连通分量
#include<iostream>
#include<cstring>
using namespace std;
struct ed {
int to,next;
} a[1000001];
int head[300001];
int n,m,q,t,ans;
int dfn[300001],low[300001],scc[300001],cnt,in;
bool vis[1000001];
void tarjan(int u,int fa) {
dfn[u]=low[u]=++in;
for(int i=head[u]; i!=-1; i=a[i].next) {
if((i^1)==fa)continue;
int v=a[i].to;
if(!dfn[v]) {
tarjan(v,i);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]){
vis[i]=vis[i^1]=true;
}
} else {
low[u]=min(low[u],dfn[v]);
}
}
}
void dfs(int u) {
scc[u]=cnt;
for(int i=head[u]; i!=-1; i=a[i].next) {
int v=a[i].to;
if(!scc[v]&&!vis[i])dfs(v);
}
}
void add(int u,int v) {
a[t].to=v;
a[t].next=head[u];
head[u]=t++;
}
int main() {
cin>>n>>m>>q;
memset(head,-1,sizeof(head));
while(m--) {
int x,y;
cin>>x>>y;
add(x,y),add(y,x);
}
for(int i=1; i<=n; i++) {
if(!dfn[i])tarjan(i,-1);
}
for(int i=1; i<=n; i++) {
cnt++;
if(!scc[i])dfs(i);
}
return 0;
}
桥
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
struct ed {
int to,next;
} a[200001];//edge*2
int head[100001];
int n,m,in,dfn[100001],low[100001];
bool vis[100001];
void tarjan(int u,int fa) {
dfn[u]=low[u]=++in;
for(int i=head[u]; i!=-1; i=a[i].next) {
if((i^1)==fa)continue;
int v=a[i].to;
if(!dfn[v]) {
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])vis[i]=vis[i^1]=true;
} else {
low[u]=min(low[u],dfn[v]);
}
}
}
int main() {
cin>>n>>m;
while(m--) {
int u,v;
cin>>u>>v;
add(u,v),add(v,u);
}
for(int i=1;i<=n;i++){
if(!dfn[i])tarjan(i,-1);
}
return 0;
}
割点
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
bool vis[10001];
int n,m,in,sum,dfn[10001],low[10001],cnt[10001];
vector<int>g[10001];
void tarjan(int u,int fa) {
dfn[u]=low[u]=++in;
int c=0;
for(int i=0; i<g[u].size(); i++) {
int v=g[u][i];
if(v==fa)continue;
if(!dfn[v]) {
c++;
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])iscp=true;
} else {
low[u]=min(low[u],dfn[v]);
}
}
if(fa==-1&&c<=1)iscp[u]=false;
}
int main() {
cin>>n>>m;
while(m--) {
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1; i<=n; i++) {
if(!dfn[i])tarjan(i,-1);
}
return 0;
}
强连通分量
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
vector<int> g[10001];
int n,m,x,y,dfn[10001],low[10001],scc[10001],cnt,index;
stack<int> st;
void tarjan(int u){
dfn[u]=low[u]=++index;
st.push(u);
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else{
if(!scc[v])low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
cnt++;
int v;
do{
v=st.top();
st.pop();
scc[v]=cnt;
}while(u!=v);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>x>>y;
g[x].push_back(y);
}
for(int i=1;i<=n;i++){
if(!dfn[i])tarjan(i);
}
return 0;
}