1. 程式人生 > >POJ3694 Network【連通分量+LCA】

POJ3694 Network【連通分量+LCA】

-- wap 題意 fin div ace code swap ext

題意:

一個無向圖可以有重邊,下面q個操作,每次在兩個點間連接一條有向邊,每次連接後整個無向圖還剩下多少橋(註意是要考慮之前連了的邊,每次回答是在上一次的基礎之上)。

思路:

首先運行一次Tarjan,求出橋和縮點,那麽遠無向圖將縮點為一棵樹,樹邊正好是原來的橋。每次連接兩點,看看這兩點是不是在同一個縮點內,如果是,那麽縮點後的樹沒任何變化,如果兩點屬於不同的縮點,那麽連接起來,然後找這兩個縮點的LCA,因為從點u到LCA再到點v再到點u,將形成環,裏面的樹邊都會變成不是橋。計數的時候註意,有些樹邊可能之前已經被標記了,這次再經過不能再標記。

代碼:

#include <iostream>
#include 
<cstdio> #include <cstring> #include <vector> using namespace std; #define N 100010 #define M 200010 vector<int> ver[N]; int head[N],dfn[N],low[N],vis[N],fa[N],dcnt,bcnt; struct edge{ int u,v,used,next; }e[2*M]; bool isbridge[N]; inline void add(int u, int v ,int &k) { e[k].v
= v; e[k].used = 0; e[k].next = head[u]; head[u] = k++; } void LCA(int u,int v) { if(dfn[u] < dfn[v]) swap(u,v); while(dfn[u] > dfn[v]) { if(isbridge[u]) bcnt--; isbridge[u] = false; u = fa[u]; } while(u!=v) { if(isbridge[u]) bcnt--;
if(isbridge[v]) bcnt--; isbridge[u] = isbridge[v] = false; u = fa[u]; v = fa[v]; } } void dfs(int u) { vis[u] = 1; dfn[u] = low[u] = ++dcnt; for(int k=head[u]; k!=-1; k=e[k].next) if(!e[k].used) { e[k].used = e[k^1].used = 1; int v = e[k].v; if(!vis[v]) { fa[v] = u; dfs(v); low[u] = min(low[u] , low[v]); if(dfn[u] < low[v]) { bcnt++; isbridge[v] = true; } } else if(vis[v] == 1) low[u] = min(low[u],dfn[v]); } vis[u] = 2; } int main() { int n,m,q,cas=0; while(cin>>n>>m,n,m) { memset(head,-1,sizeof(head)); int k = 0; for(int i=0; i<m; i++) { int u,v; cin>>u>>v; add(u,v,k); add(v,u,k); } memset(isbridge,false,sizeof(isbridge)); memset(vis,0,sizeof(vis)); dcnt = bcnt = 0; fa[1] = 1; dfs(1); printf("Case %d:\n",++cas); cin>>q; while(q--) { int u,v; cin>>u>>v; LCA(u,v); cout<<bcnt<<endl; } cout<<endl; } return 0; }

POJ3694 Network【連通分量+LCA】