POJ 3694 Network【LCA】
题意: 给定一个无向图,图中存在一些桥,之后向图中加入Q条边,问每次加入这条边后图中剩下的桥的数量。
分析: 首先对无向图求割边,并进行缩点,使之成为一棵树,这棵树上的所有边都是割边,之后对于每次询问,会连接树上的两个节点,如果这两个节点之间的边与这条边形成一个环,那么这些边就不再是割边,对于缩点后的树,先随意定出一个根,之后对每个节点记录他的父节点,以及他在这棵树中的深度,之后对于每次询问只要从叶子节点一直搜到他们的lca,把路径上的割边去掉。
#include<stdio.h> #include<string.h> #include<stdlib.h> #define maxn 200005 #define max(a,b)(a)>(b)?(a):(b) #define min(a,b)(a)<(b)?(a):(b) #define clr(x)memset(x,0,sizeof(x)) struct node { int to,next; }e[600005]; int tot; int head[maxn]; void add(int s,int u) { e[tot].to=u; e[tot].next=head[s]; head[s]=tot++; } int ti; int num; int dfn[maxn],low[maxn]; int br[maxn]; int f[maxn]; int ins[maxn]; void tarjan(int p,int u) { dfn[u]=low[u]=++ti; ins[u]=1; int i,k; for(i=head[u];i;i=e[i].next) { k=e[i].to; if(k==p) continue; if(ins[k]) low[u]=min(low[u],dfn[k]); else { f[k]=u; tarjan(u,k); low[u]=min(low[u],low[k]); if(low[k]>dfn[u]) { br[k]=1; num++; } } } } int sta[maxn]; int top; void LCA(int x,int y) { sta[0]=x; sta[1]=y; top=2; while(x!=y) { if(dfn[x]>dfn[y]){ if(br[x]) { num--; br[x]=0; } sta[top++]=(x=f[x]); } else if(dfn[x]<dfn[y]) { if(br[y]) { num--; br[y]=0; } sta[top++]=(y=f[y]); } } while(top--) if(sta[top]!=x) f[sta[top]]=x; } int main() { int n,m,a,b,ca=1; while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0) break; tot=1; ti=0; num=0; clr(head); clr(br); clr(ins); while(m--) { scanf("%d%d",&a,&b); add(a,b); add(b,a); } f[1]=1; tarjan(0,1); printf("Case %d:\n",ca++); scanf("%d",&m); while(m--) { scanf("%d%d",&a,&b); LCA(a,b); printf("%d\n",num); } printf("\n"); } return 0; }