kuangbin專題 專題九 連通圖 POJ 3694 Network

題目連接:https://vjudge.net/problem/POJ-3694node

題目:給定一個連通圖,求橋的個數,每次查詢,加入一條邊,問加入這條邊後還有多少個橋。ios

思路:tarjan + 並查集 + lca(樸素)函數

先用tarjan縮點(成環縮點),並存下橋,把每一個scc都存下一個源點(源點(boss):以這個點表明這個scc)。優化

用存下的橋,用並查集從新建圖,爲了方便以後的操做,並查集創建一顆樹,dfn小的在上,dfn大的在下。ui

lca,用每一個點的boss的dfn去跑lca,由於咱們建樹的方法,總會遇到公共的dfn祖先,把這些點都存下,spa

最後把這些boss點的dfn都變成祖先的dfn值,這樣優化了重複的lca,以後輸出答案便可。.net

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <vector>
 5 using namespace std;  6 #define pb push_back
 7 
 8 const int N = (int)5e5+10;  9 int n,m,tot,tim,top,scc,ans;//點,邊,鏈式前向星,時間戳,棧,連通數
 10 int head[N],dfn[N],low[N],scc_no[N],s[N],fa[N],boss[N];  11 //鏈式前向星,dfn,low,聯通塊編號,棧,父節點,源點
 12 struct node{  13     int to;  14     int nxt;  15 }e[N << 1];  16 struct _cut{  17     int x,y;  18 };  19 vector<_cut> cut;//
 20 vector<int> poi;//lca
 21 
 22 void init(){  23     for(int i = 0; i <= n; ++i){  24         head[i] = -1;  25         dfn[i] = 0;  26  }  27  cut.clear();  28     scc = tim = tot = 0;  29 }  30 
 31 inline void add(int u,int v){  32     e[tot].to = v;  33     e[tot].nxt = head[u];  34     head[u] = tot++;  35 }  36 
 37 void tarjan(int now,int pre){  38     dfn[now] = low[now] = ++tim;  39     s[top++] = now;  40 
 41     int to,pre_cnt = 0;  42     for(int o = head[now]; ~o; o = e[o].nxt){  43         to = e[o].to;  44         if(to == pre && pre_cnt == 0) { pre_cnt = 1; continue; }  45         if(!dfn[to]){  46  tarjan(to,now);  47             low[now] = min(low[now],low[to]);  48             if(dfn[now] < low[to]) cut.pb(_cut{now,to});  49  }  50         else if(low[now] > dfn[to]) low[now] = dfn[to];  51  }  52 
 53     if(dfn[now] == low[now]){  54         int p;  55         ++scc;  56         fa[now] = now; boss[scc] = now;//記錄該scc的源點
 57         do{  58             p = s[--top];  59             scc_no[p] = scc;  60         }while(now != p);  61  }  62 }  63 //獲得源點函數
 64 inline int _boss(int x){  65     return boss[scc_no[x]];  66 }  67 //重建圖 boss進行並查集
 68 void rebuild(){  69     ans = cut.size();  70     int x,y;  71     for(int i = 0; i < ans; ++i){  72         x = _boss(cut[i].x);  73         y = _boss(cut[i].y);  74         //dfn上小,下大的樹
 75         if(dfn[x] > dfn[y]) swap(x,y);  76         fa[y] = x;  77  }  78 }  79 
 80 void lca(int x,int y){  81     int fax = _boss(x);  82     int fay = _boss(y);  83     if(dfn[fax] == dfn[y]) return;  84 
 85  poi.pb(fax); poi.pb(fay);  86     while(dfn[fax] != dfn[fay]){  87         while(dfn[fax] > dfn[fay]){  88             --ans;  89             fax = fa[fax];  90  poi.pb(fax);  91  }  92         while(dfn[fax] < dfn[fay]){  93             --ans;  94             fay = fa[fay];  95  poi.pb(fay);  96  }  97  }  98 
 99     int n = poi.size();//全部boss點dfn改變爲祖先的dfn
100     for(int i = 0; i < n; ++i) dfn[poi[i]] = dfn[fax]; 101  poi.clear(); 102 } 103 
104 int main(){ 105 
106     int _case = 0; 107     while(~scanf("%d%d",&n,&m) && (n+m)){ 108  init(); 109         int u,v; 110         for(int i = 0; i < m; ++i){ 111             scanf("%d%d",&u,&v); 112  add(u,v); add(v,u); 113  } 114 
115         tarjan(1,1); 116  rebuild(); 117 
118         int q; 119         scanf("%d",&q); 120         printf("Case %d:\n",++_case); 121         while(q--){ 122             scanf("%d%d",&u,&v); 123  lca(u,v); 124             printf("%d\n",ans); 125  } 126  } 127 
128 
129 
130     return 0; 131 }
相關文章
相關標籤/搜索