题意是给一个无向图,q个询问,每次询问加上一条边之后剩余的桥的数量。
首先就是缩成一个只有桥的图,此时就会缩成一颗树,这时减少的桥就是询问的两点到他们的lca的距离,由于询问只有1000,所以LCA写暴力就可以实现。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
const int maxm=400005;
const int maxn=100005;
struct edge{
int to,nxt;
}e[maxm];
int n,m,q,x,y;
int head[maxn],low[maxn],dfn[maxn],depth[maxn];
bool bridge[maxn];
int fa[maxn];
int tim,ecnt,cnt;
void ins(int u,int v){
e[ecnt].to=v;
e[ecnt].nxt=head[u];
head[u]=ecnt++;
}
void init(){
tim=ecnt=cnt=0;
mem(head,-1);
mem(depth,0);
mem(low,0);
mem(dfn,0);
mem(bridge,0);
for(int i=1;i<=n;i++) fa[i]=i;
}
void tarjan(int u){
dfn[u]=low[u]=++tim;
depth[u]=depth[fa[u]]+1;
for(int i=head[u];i!=-1;i=e[i].nxt){
int v=e[i].to;
if(!dfn[v]){
fa[v]=u;
tarjan(v);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]){
cnt++;
bridge[v]=1;
}
}else if(v!=fa[u]) low[u]=min(low[u],dfn[v]);
}
}
void LCA(int u,int v){
while(depth[u]<depth[v]){
if(bridge[v]){
bridge[v]=0;
cnt--;
}
v=fa[v];
}
while(depth[u]>depth[v]){
if(bridge[u]){
bridge[u]=0;
cnt--;
}
u=fa[u];
}
while(u!=v){
if(bridge[u]){
bridge[u]=0;
cnt--;
}u=fa[u];
if(bridge[v]){
bridge[v]=0;
cnt--;
}v=fa[v];
}
}
int cas;
int main(){
while(~scanf("%d%d",&n,&m)){
if(n==m&&n==0) break;
init();
printf("Case %d:\n",++cas);
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
ins(x,y),ins(y,x);
}
tarjan(1);
scanf("%d",&q);
while(q--){
scanf("%d%d",&x,&y);
LCA(x,y);
printf("%d\n",cnt);
}
printf("\n");
}
return 0;
}