1. 程式人生 > >poj3694 Network 邊雙連通分量

poj3694 Network 邊雙連通分量

題解:

邊雙模板。
邊雙的求法比較簡單,先求出所有割邊,然後不走割邊,dfs一下,就可以找出所有了。
做法顯然是先對原圖跑一遍邊雙,然後每次加一條邊,若兩點屬於同一個邊雙連通分量,那麼答案不會改變;否則這兩個連通分量路徑上的邊全都變成非割邊。這個當然可以可以用樹鏈剖分,但是看了題解有更為簡潔的做法:用並查集維護每個點往上的第一條割邊,這樣每條邊只會被刪一次,程式碼寫起來也十分簡單。

程式碼:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std; #define LL long long #define pa pair<int,int> const int Maxn=100010; const int Maxm=200010; const int inf=2147483647; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3
)+(x<<1)+(ch^48),ch=getchar(); return x*f; } int n,m,q,Case=0; struct Edge{int y,next;}e[Maxm<<1],E[Maxm<<1]; int last[Maxn],len; void ins(int x,int y) { int t=++len; e[t].y=y;e[t].next=last[x];last[x]=t; } int Last[Maxn],Len; void Ins(int x,int y) { int t=++Len; E[t].y=y;E[t].next=Last[x];Last[x]=t; } int
dfn[Maxn],low[Maxn],id,sta[Maxn],top,cnt,bel[Maxn],rt[Maxn],fa[Maxn][17],dep[Maxn]; bool mark[Maxm<<1],vis[Maxn]; void Tarjan(int x,int p) { low[x]=dfn[x]=++id; sta[++top]=x; for(int i=last[x];i;i=e[i].next) { int y=e[i].y; if(i==p||i==(p^1))continue; if(!dfn[y]) { Tarjan(y,i);low[x]=min(low[x],low[y]); if(low[y]>dfn[x])mark[i]=mark[i^1]=true; } else low[x]=min(low[x],dfn[y]); } } void dfs(int x) { vis[x]=true; bel[x]=cnt; for(int i=last[x];i;i=e[i].next) { if(mark[i])continue; int y=e[i].y; if(vis[y])continue; dfs(y); } } void DFS(int x,int f) { fa[x][0]=f;dep[x]=dep[f]+1; for(int i=1;(1<<i)<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1]; for(int i=Last[x];i;i=E[i].next) { int y=E[i].y; if(y==f)continue; DFS(y,x); } } int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=16;i>=0;i--) if((1<<i)<=dep[x]-dep[y])x=fa[x][i]; if(x==y)return x; for(int i=16;i>=0;i--) if((1<<i)<=dep[x]&&fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int findrt(int x) { if(rt[x]==x)return x; rt[x]=findrt(rt[x]); return rt[x]; } int main() { while(1) { n=read(),m=read(); if(!n&&!m)break; Case++; memset(last,0,sizeof(last));len=1; memset(Last,0,sizeof(Last));Len=1; int ans=0; memset(mark,false,sizeof(mark)); memset(vis,false,sizeof(vis)); for(int i=1;i<=m;i++) { int x=read(),y=read(); ins(x,y),ins(y,x); } top=cnt=id=0; memset(dfn,0,sizeof(dfn)); Tarjan(1,0); for(int i=1;i<=n;i++) if(!vis[i])cnt++,dfs(i); for(int i=2;i<=len;i+=2) { int x=e[i].y,y=e[i^1].y; if(bel[x]==bel[y])continue; Ins(bel[x],bel[y]),Ins(bel[y],bel[x]); ans++; } dep[0]=-1;DFS(1,0); for(int i=1;i<=cnt;i++)rt[i]=i; q=read(); printf("Case %d:\n",Case); while(q--) { int x=read(),y=read(); x=bel[x],y=bel[y]; if(x==y){printf("%d\n",ans);continue;} int z=LCA(x,y); while(1) { int t=findrt(x); if(dep[t]<=dep[z])break; ans--;rt[x]=rt[rt[fa[t][0]]];x=fa[t][0]; } while(1) { int t=findrt(y); if(dep[t]<=dep[z])break; ans--;rt[y]=rt[rt[fa[t][0]]];y=fa[t][0]; } printf("%d\n",ans); } puts(""); } }