题意:给你一个无向连通图,让后给出每给q条要添加的边,输出添加每一条边之后图中还剩下多少桥
分析:向图中加入边那么就有可能是得图中的桥减小,那么我们可以先求出图中的双连通分量,那么若添加的一条边是属于某个双连通分量的那么桥的条数没有减少,如果这条边的两个顶点分别属于两个双连通子图,那么从就会使桥的数目减小,那么问题就分为两步来解决: 1、求出双连通分量后和缩点 2、加入一条边后求出桥减少的条数
第一步很好解决,这里就不赘述!
第二步:因为缩点之后新图就是一颗树,向该树中添加一条边,那么树中就会形成一条环(就形成了一个双连通分量),那么这个环上的边(当然不包含添加的那条边)就是减少的桥的条数,那么我们现在的任务就是找出加边之后形成的环中的边,那么我们可以用暴力lca(具体的见代码)
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 100005;
const int E = 400005;
struct node
{
int x,y,nxt;
}edge[E],edge1[E];
int e, head[N];
int e1,first[N];
int cnt;
int Min(int a,int b)
{
return a>b?b:a;
}
void addedge(int x, int y)
{
edge[e].x=x;
edge[e].y=y;
edge[e].nxt=head[x];
head[x]=e++;
edge[e].x=y;
edge[e].y=x;
edge[e].nxt=head[y];
head[y]=e++;
}
void add(int x,int y)
{
edge1[e1].x=x;
edge1[e1].y=y;
edge1[e1].nxt=first[x];
first[x]=e1++;
}
int dfn[N],low[N],index,top,st[N],blg[N];
void Cutedge(int u, int fa)
{
int v,x;
low[u]=dfn[u]=index++;
st[++top]=u;
bool tag=false;
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
v=edge[i].y;
if(v==fa&&tag==false){tag=true;continue;}//处理重边
if(dfn[v]==-1)
{
Cutedge(v,u);
low[u]=Min(low[u],low[v]);
if(low[v]>dfn[u])
{
cnt++;
do
{
x=st[top];
top--;
blg[x]=cnt;
}while(x!=v);
}
}
else low[u]=Min(low[u],dfn[v]);
}
}
int pre[N],father[N];
void dfs(int u, int fa)
{
//pre[u]=fa;
for(int i=first[u];i!=-1;i=edge1[i].nxt)
{
int v = edge1[i].y;
if(fa==v)continue;
pre[v]=u;
dfs(v,u);
}
}
int tag[N];
bool vis[N];
int lca(int x, int y,int c)
{
int num,ans;
if(x==y)
return 0;
tag[x]=c;tag[y]=c;
int x1=x;
int y1=y;
while(1)
{
if(x1!=pre[x1])
{
x1=pre[x1];
if(tag[x1]==c){ans=x1;break;}
tag[x1]=c;
}
if(y1!=pre[y1])
{
y1=pre[y1];
if(tag[y1]==c){ans=y1;break;}
tag[y1]=c;
}
}
num=0;
while(x!=ans)
{
if(vis[x]==0)
{vis[x]=1;num++;}
x=pre[x];
}
while(y!=ans)
{
if(vis[y]==0)
{vis[y]=1;num++;}
y=pre[y];
}
return num;
}
int main ()
{
int n, m,k=1;
int i,x,y,q;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)break;
e = 0;
memset(head,-1,sizeof(head));
for(i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
addedge(x,y);
}
memset(dfn,-1,sizeof(dfn));
memset(low,0,sizeof(low));
index=1;
top=0;
cnt=0;
Cutedge(1,-1);//求割边且缩点
cnt++;
while(top!=0)
{
blg[st[top]]=cnt;
top--;
}
e1=0;
memset(first,-1,sizeof(first));
for(i=0;i<e;i++)//缩点建图
{
x=blg[edge[i].x];
y=blg[edge[i].y];
if(x==y)continue;
add(x,y);
}
/* for(i=1;i<=cnt;i++)
for(int j=first[i];j!=-1;j=edge1[j].nxt)
printf("%d %d \n",i,edge1[j].y);*/
dfs(1,1);
// for(i=1;i<=cnt;i++)
// printf("%d ",pre[i]);
// cout << endl;
cnt--;
scanf("%d",&q);
printf("Case %d:\n",k++);
memset(vis,0,sizeof(vis));
memset(tag,0,sizeof(tag));
for(i=1;i<=q;i++)
{
scanf("%d%d",&x,&y);
x=blg[x];
y=blg[y];
// cout << x<<" " << y << endl;
int num=lca(x,y,i);
printf("%d\n",cnt-num);
cnt-=num;
}
printf("\n");
}
return 0;
}