poj3694 Network 邊雙連通分量
阿新 • • 發佈:2018-11-19
題解:
邊雙模板。
邊雙的求法比較簡單,先求出所有割邊,然後不走割邊,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("");
}
}