poj 3529 Network 双连通分连 动态求桥的数目 + tarjan离线算法求LCA
题意:一开始有n个点m条边,后来每次加一条边,求加上这一条边后途中有几座“桥”。
分析:双连通分量
View Code
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define maxn 100010 struct Edge{ int u,v,next; int vis; }edge[1000005]; int head[maxn]; int E=0; void addedge(int u,int v){ edge[E].u=u;edge[E].v=v;edge[E].vis=0; edge[E].next=head[u];head[u]=E++; } int Time,N,M; int dfn[maxn],low[maxn]; int Top; int bridge; int f[maxn]; bool mark[maxn]; int find(int x) { return x==f[x]?x:f[x]=find(f[x]); } void dfs(int u){ int v; dfn[u]=low[u]=++Time; for(int i=head[u];i!=-1;i=edge[i].next){ if(edge[i].vis) continue; edge[i].vis=edge[i^1].vis=1; v=edge[i].v; if(!dfn[v]){ f[v]=u; dfs(v); low[u]=min(low[u],low[v]); } else low[u]=min(low[u],dfn[v]); if(low[v]<=dfn[u]) { int x=find(v); int y=find(u); if(x!=y) f[x]=y; } if(low[v]>dfn[u]){ mark[v]=true; bridge++; } } } void SCC(int n){ bridge=0;f[1]=1; memset(mark,false,sizeof(mark)); memset(dfn,0,sizeof(int)*(n+1)); for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i); } void LCA(int a,int b){ if(dfn[a]<dfn[b]){ a^=b; b^=a; a^=b; } while(dfn[a]>dfn[b]){ if(mark[a]) { bridge--;mark[a]=false; } a=f[a]; } while(a!=b){ if(mark[a]) { bridge--;mark[a]=false; } a=f[a]; if(mark[b]) { bridge--;mark[b]=false; } b=f[b]; } } int main(){ int n,m,i,q,a,b,ca=1; while(~scanf("%d%d",&n,&m) && n){ E=0; memset(head,-1,sizeof(head)); for(i=0;i<m;i++){ scanf("%d%d",&a,&b); addedge(a,b); addedge(b,a); } SCC(n); printf("Case %d:\n",ca++); scanf("%d",&q); while(q--){ scanf("%d%d",&a,&b); LCA(a,b); printf("%d\n",bridge); } printf("\n"); } return 0; }