边双的经典例题,动态加边只需要在加边的两点网上求父节点到lca,将其中的的桥去掉后路径压缩
#include<bits/stdc++.h> using namespace std; const int N=4e5+10; int isce[N],h[N],ne[N],e[N],idx; int dfn[N],low[N],fa[N],depth[N]; int times,n,m,ans; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void init(){ memset(h,-1,sizeof h); memset(dfn,0,sizeof dfn); memset(low,0,sizeof low); memset(fa,0,sizeof fa); memset(depth,0,sizeof depth); memset(isce,0,sizeof isce); ans=0,times=0; } void tarjan(int u){ dfn[u]=low[u]=++times; int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(!dfn[j]){ fa[j]=u,depth[j]=depth[u]+1; tarjan(j); low[u]=min(low[u],low[j]); if(dfn[u]<low[j]){ ++ans; isce[j]=1; } } else if(j!=fa[u]) low[u]=min(low[u],dfn[j]); } } int num[N]; void lca(int a,int b){ if(depth[a]<depth[b]) swap(a,b); int top=0; while(depth[a]>depth[b]){ num[++top]=a; if(isce[a]){ ans--; isce[a]=0; } a=fa[a]; } while(a!=b){ num[++top]=a; num[++top]=b; if(isce[a]){ ans--; isce[a]=0; } if(isce[b]){ ans--; isce[b]=0; } a=fa[a]; b=fa[b]; } for(int i=1;i<=top;i++){ fa[num[i]]=a; } } int main(){ ios::sync_with_stdio(false); int sign=1; while(cin>>n>>m){ if(n==0&&m==0) break; int i; init(); cout<<"Case "<<sign++<<":"<<endl; for(i=1;i<=m;i++){ int a,b; cin>>a>>b; add(a,b); add(b,a); } for(i=1;i<=n;i++){ if(!dfn[i]){ fa[i]=i; tarjan(i); } } int q; cin>>q; while(q--){ int a,b; cin>>a>>b; lca(a,b); cout<<ans<<endl; } cout<<endl; } return 0; }