tarjan缩点+lca
题目让求桥,先跑一遍tarjan,缩点并求出桥的数目,两点属于同一联通分量,那么输出桥的数目。如果不是,那么求出它们的lca,则两点上推至lca的所有点都不再是桥,因为成环了
话说没想到lca这么简单,虽说办法朴素了些,但是基于tarjan的那个我也学会了,它非常好的利用了dfs的性质,以后再整理吧
#include
#include
#include
using namespace std;
const int N = 100100;
const int M = 200200;
int head[N], head2[N];
int dfn[N], low[N], father[N];
int deep[N];
int block[N], pre[N], st[N];
bool instack[N];
int tot, tot2, top, ord, sccnum, icase;
struct node{
int next;
int to;
int id;
}edge[M * 4], edge2[M * 4];
void init(){
memset(dfn, -1, sizeof(dfn));
memset(head, -1, sizeof(head));
memset(head2, -1, sizeof(head2));
memset(low, 0, sizeof(low));
memset(instack, 0, sizeof(instack));
tot = tot2 = ord = sccnum = top = 0;
}
void addedge(int from, int to, int id){
edge[tot]. to = to;
edge[tot]. id = id;
edge[tot]. next = head[from];
head[from] = tot ++;
}
void addedge2(int from, int to){
edge2[tot2]. to = to;
edge2[tot2]. next = head2[from];
head2[from] = tot2 ++;
}
void dfs(int u, int fa, int d){
pre[u] = fa;
deep[u] = d;
for(int i = head2[u]; ~i; i = edge2[i]. next){
int v = edge2[i]. to;
if(v == fa)
continue;
dfs(v, u, d + 1);
}
}
int find(int x){
if(x == father[x])
return x;
return father[x] = find(father[x]);
}
void tarjan(int u, int x){
dfn[u] = low[u] = ++ ord;
instack[u] = true;
st[top ++] = u;
for(int i = head[u]; ~i; i = edge[i]. next){
int v = edge[i]. to;
if(edge[i]. id == x)
continue;
if(dfn[v] == -1){
tarjan(v, edge[i]. id);
low[u] = min(low[u], low[v]);
}
else if(instack[v]){
low[u] = min(low[u], dfn[v]);
}
}
int v;
if(dfn[u] == low[u]){
++ sccnum;
do{
v = st[-- top];
instack[v] = false;
block[v] = sccnum;
}while(v != u);
}
}
int LCA(int a, int b){
while(a != b){
if(deep[a] > deep[b])
a = pre[a];
else if(deep[a] < deep[b])
b = pre[b];
else{
a = pre[a];
b = pre[b];
}
a = find(a);
b = find(b);
}
return a;
}
void solve(int n){
tarjan(1, -1);
for(int u = 1; u <= n; u ++){
for(int i = head[u]; ~i; i = edge[i]. next){
int v = edge[i]. to;
if(block[u] == block[v])
continue;
addedge2(block[u], block[v]);
}
}
for(int i = 1; i <= sccnum; i ++)
father[i] = i;
int cnt = sccnum - 1;
dfs(1, -1, 0);
int q, a, b, lca;
scanf("%d", &q);
printf("Case %d:\n", icase++);
while(q --){
scanf("%d %d", &a, &b);
a = block[a];
b = block[b];
if(a == b){
printf("%d\n", cnt);
continue;
}
a = find(a);
b = find(b);
lca = LCA(a, b);
int x = 0;
while(a != lca){
x ++;
father[a] = lca;
a = pre[a];
a = find(a);
}
while(b != lca){
x ++;
father[b] = lca;
b = pre[b];
b = find(b);
}
cnt -= x;
printf("%d\n", cnt);
}
}
int main(){
int n, m;
int u, v;
icase = 1;
while(~scanf("%d %d", &n, &m)){
if(!n && !m)
break;
init();
for(int i = 1; i <= m; i ++){
scanf("%d %d", &u, &v);
addedge(u, v, i);
addedge(v, u, i);
}
solve(n);
printf("\n");
}
return 0;
}