/***
dfs遍历一遍整个图,标出时间戳 dfs_clock,保存在pre[]里
遍历后得到一个森林
对于每一颗树,每个节点是割顶的情况:
1:根: 有两个或两个以上的子节点
2:非根: 对于节点u,low(u)表示u及u的所有节点的反向边所能连回的最早的节点的pre[]值
如果u的所有子节点的low[v]>=pre[u]; 那么u节点就是割顶
特别的,如果low[u]>pre[u],边(u,v)还是一个桥
初始化是,假设所有的low(u)=u;即所有节点都能连回自己
***/
1:
int head[MAXN],pre[MAXN],low[MAXN],cnt,dfs_clock;
bool iscut[MAXN],isedgecut[MAXM];///true表示是割顶
struct Edge{
int v;
int next,to;
}edge[MAXM>>1];
void add(int u,int v){
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void init(){
cnt = dfs_clock = 0;
memset(head,-1,sizeof(head));
memset(pre,0,sizeof(pre));
}
void dfs(int u,int fa){
low[u] = pre[u] = ++dfs_clock;
int child = 0;
*****int lowv = dfs_clock+1;
for(int i = head[u];i != -1;i = edge[i].next){
int v = edge[u].to;
if(!pre[v]){
child++;
dfs(v,u);
*****lowv = min(lowv,low[v]);
low[u] = min(low[u],low[v]);
if(low[v] >= pre[u]) iscut[u] = true;///这个地方也可以改成vector,找的时候更快
*****if(low[v] > pre[u]) isedgecut[i] = true;///找到的桥
}
else if(v != fa && pre[v] < pre[u]){
low[u] = min(low[u],pre[v]);
}
}
if(fa == -1 && child > 1) iscut[u]=true;
*****if(fa == -1 && lowv != u){
for(int i = head[u];i != -1;i = edge[i].next) isedgecut[i]=true;
}
}
2:
vector <int> G[MAXN];
*****vector < pair<int,int> > edge;
void dfs(int u,int fa){
low[u] = pre[u] = ++dfs_clock;
int child = 0;
*****int lowv = dfs_clock+1;
for(int i = 0;i < G[u].size();i++){
int v = G[u][v];
if(!pre[v]){
child++;
dfs(v,u);
*****lowv = min(lowv,low[v]);
low[u] = min(low[u],low[v]);
if(low[v] >= pre[u]) iscut[u] = true;
*****if(low[v] > pre[u]) edge.push_back(mak_pair(u,v));
}
else if(v != fa && pre[v] < pre[u]){
low[u] = min(low[u],pre[v]);
}
}
if(fa == -1 && child > 1) iscut[u] = true;
*****if(fa == -1 && lowv != u){
for(int i = 0;i < G[u].size();i++) edge.push_back(make_pair(u,v));
}
}