一共有N个点,m条边,无向图,q次询问,每次添加一个边,问添加完边后还剩多少 桥 。
用tarjan边连通计算 初始桥的个数。LCA计算添加边之后桥的个数。
并查集用来 把每一个边连通分量联系在一起。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N = 1e5+10;
struct node{
int to;
int next;
}edge[N<<2];
int head[N],top;
int dfn[N],low[N],time;
int uset[N],fa[N],bridgeNum;
bool bridge[N];
void init(int n){
memset(dfn,0,sizeof(dfn));
memset(head,-1,sizeof(head));
memset(bridge,false,sizeof(bridge));
for(int i = 0; i <= n; ++i){
uset[i] = i;
fa[i] = i;
}
top = time = bridgeNum = 0;
}
int found(int x){
return x==uset[x]?x:uset[x]=found(uset[x]);
}
bool unionset(int x,int y){
x = found(x);
y = found(y);
if(x==y)return false;
uset[x] = y;
return true;
}
void add(int u,int v){
edge[top]={v,head[u]};
head[u] = top++;
}
void tarjan(int u,int father){
low[u] = dfn[u] = ++time;
for(int i = head[u]; ~i; i=edge[i].next){
int& v = edge[i].to;
if(father==v)continue;
if(!dfn[v]){
fa[v] = u;
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(low[v] > dfn[u]){
bridgeNum++;
bridge[u] = true;
}
else{
unionset(u,v);
}
}
else if(dfn[v] < dfn[u]){
low[u] = min(low[u],dfn[v]);
}
}
}
void LCA(int u,int v){
if(dfn[u] > dfn[v])swap(u,v);
while(dfn[v] > dfn[u]){
if(unionset(v,fa[v])){
bridgeNum--;
}
v = fa[v];
}
while(dfn[u] > dfn[v]){
if(unionset(u,fa[u])){
bridgeNum--;
}
u = fa[u];
}
}
int main(){
//freopen("out.txt","w",stdout);
int n,m,q;
int u,v,t = 0;
while(scanf("%d%d",&n,&m),n||m){
init(n);
for(int i = 0; i < m; ++i){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
tarjan(1,-1);
printf("Case %d:\n",++t);
scanf("%d",&q);
while(q--){
scanf("%d%d",&u,&v);
if(bridgeNum){
LCA(u,v);
}
printf("%d\n",bridgeNum);
}
printf("\n");
}
return 0;
}