题解:
边双模板。
边双的求法比较简单,先求出所有割边,然后不走割边,dfs一下,就可以找出所有了。
做法显然是先对原图跑一遍边双,然后每次加一条边,若两点属于同一个边双连通分量,那么答案不会改变;否则这两个连通分量路径上的边全都变成非割边。这个当然可以可以用树链剖分,但是看了题解有更为简洁的做法:用并查集维护每个点往上的第一条割边,这样每条边只会被删一次,代码写起来也十分简单。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=100010;
const int Maxm=200010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,q,Case=0;
struct Edge{int y,next;}e[Maxm<<1],E[Maxm<<1];
int last[Maxn],len;
void ins(int x,int y)
{
int t=++len;
e[t].y=y;e[t].next=last[x];last[x]=t;
}
int Last[Maxn],Len;
void Ins(int x,int y)
{
int t=++Len;
E[t].y=y;E[t].next=Last[x];Last[x]=t;
}
int dfn[Maxn],low[Maxn],id,sta[Maxn],top,cnt,bel[Maxn],rt[Maxn],fa[Maxn][17],dep[Maxn];
bool mark[Maxm<<1],vis[Maxn];
void Tarjan(int x,int p)
{
low[x]=dfn[x]=++id;
sta[++top]=x;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(i==p||i==(p^1))continue;
if(!dfn[y])
{
Tarjan(y,i);low[x]=min(low[x],low[y]);
if(low[y]>dfn[x])mark[i]=mark[i^1]=true;
}
else low[x]=min(low[x],dfn[y]);
}
}
void dfs(int x)
{
vis[x]=true;
bel[x]=cnt;
for(int i=last[x];i;i=e[i].next)
{
if(mark[i])continue;
int y=e[i].y;
if(vis[y])continue;
dfs(y);
}
}
void DFS(int x,int f)
{
fa[x][0]=f;dep[x]=dep[f]+1;
for(int i=1;(1<<i)<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=Last[x];i;i=E[i].next)
{
int y=E[i].y;
if(y==f)continue;
DFS(y,x);
}
}
int LCA(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=16;i>=0;i--)
if((1<<i)<=dep[x]-dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=16;i>=0;i--)
if((1<<i)<=dep[x]&&fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int findrt(int x)
{
if(rt[x]==x)return x;
rt[x]=findrt(rt[x]);
return rt[x];
}
int main()
{
while(1)
{
n=read(),m=read();
if(!n&&!m)break;
Case++;
memset(last,0,sizeof(last));len=1;
memset(Last,0,sizeof(Last));Len=1;
int ans=0;
memset(mark,false,sizeof(mark));
memset(vis,false,sizeof(vis));
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
ins(x,y),ins(y,x);
}
top=cnt=id=0;
memset(dfn,0,sizeof(dfn));
Tarjan(1,0);
for(int i=1;i<=n;i++)
if(!vis[i])cnt++,dfs(i);
for(int i=2;i<=len;i+=2)
{
int x=e[i].y,y=e[i^1].y;
if(bel[x]==bel[y])continue;
Ins(bel[x],bel[y]),Ins(bel[y],bel[x]);
ans++;
}
dep[0]=-1;DFS(1,0);
for(int i=1;i<=cnt;i++)rt[i]=i;
q=read();
printf("Case %d:\n",Case);
while(q--)
{
int x=read(),y=read();
x=bel[x],y=bel[y];
if(x==y){printf("%d\n",ans);continue;}
int z=LCA(x,y);
while(1)
{
int t=findrt(x);
if(dep[t]<=dep[z])break;
ans--;rt[x]=rt[rt[fa[t][0]]];x=fa[t][0];
}
while(1)
{
int t=findrt(y);
if(dep[t]<=dep[z])break;
ans--;rt[y]=rt[rt[fa[t][0]]];y=fa[t][0];
}
printf("%d\n",ans);
}
puts("");
}
}