这道题其实也非常简单,只是在求割边及其个数的情况下,每次往里面加入新的边,并再次计算割边的个数。
我们用tarjan可以求出原图的桥以及个数,当然我们不能暴力加边,然后求解,那么如何求呢???
其实非常简单,我们可以LCA进行求解,我们在a和b点两个点之间加入新的边,那么相当于连通了a,b,那么原来a,b以及其LCA上的桥,变成不是桥了,为什么???很简单
我加入这条新的边以后,那么从这两个点,到LCA组成了一个环,我们知道环上面的线一定不是桥,所以我们,可以通过寻找LCA,计算出我们减少的桥。
#include<iostream> #include<string.h> #include<algorithm> #include<stdio.h> using namespace std; const int SIZE = 400010; int head[SIZE],ver[SIZE*2],Next[SIZE*2]; int dfn[SIZE],low[SIZE],fa[SIZE],depth[SIZE],n,m,tot,num; bool brige[SIZE*2]; int cnt; void add(int x,int y){ ver[++tot]=y,Next[tot]=head[x],head[x]=tot; } void tarjan(int x,int pre){ dfn[x]=low[x]=++num; depth[x]=depth[pre]+1; for (int i=head[x];i;i=Next[i]){ int y=ver[i]; if (y==pre)continue; if (!dfn[y]){ fa[y]=x; tarjan(y,x); low[x]=min(low[x],low[y]); if (low[y]>dfn[x]){ cnt++; brige[y]=1; } }else low[x]=min(low[x],dfn[y]); } } void LCA(int u,int v){ /* */ while(depth[u]<depth[v]){ /* 如果u的高度比v的高度低的话,不断把u往上调整 */ if (brige[v]){ brige[v]=0; cnt--; } v=fa[v]; } while(depth[u]>depth[v]){ /* 反之 */ if (brige[u]){ brige[u]=0; cnt--; } u=fa[u]; } /* 如果两者在同一高度,那么我们对他们进行同时调整,把他们往上调整,直到到LCA */ while(u!=v){ if (brige[u]){ brige[u]=0; cnt--; } if (brige[v]){ brige[v]=0; cnt--; } u=fa[u]; v=fa[v]; } } void init(){ memset(head,0,sizeof(head)); memset(ver,0,sizeof(ver)); memset(Next,0,sizeof(Next)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); for (int i=1;i<=n;i++){ fa[i]=i; } cnt=0; tot=1; } int main(){ int n,q,m; int u,v; int ca=1; while(~scanf("%d%d",&n,&m)){ if (n==0 && m==0)break; init(); for (int i=1;i<=m;i++){ scanf("%d%d",&u,&v); add(u,v); add(v,u); } tarjan(1,0); scanf("%d",&q); printf("Case %d: ",ca++); while(q--){ scanf("%d%d",&u,&v); LCA(u,v); printf("%d ",cnt); } } return 0; }