kuangbin专题 专题九 连通图 POJ 3694 Network

题目链接:https://vjudge.net/problem/POJ-3694

题目:给定一个连通图,求桥的个数,每次查询,加入一条边,问加入这条边后还有多少个桥。

思路:tarjan + 并查集 + lca(朴素)

先用tarjan缩点(成环缩点),并存下桥,把每个scc都存下一个源点(源点(boss):以这个点代表这个scc)。

用存下的桥,用并查集重新建图,为了方便之后的操作,并查集建立一颗树,dfn小的在上,dfn大的在下。

并且标记x和fa[x]之间有桥,在lca过程中,如果fa[x].bridge == 1,说明这个桥仍然存在,然后fa[x].bridge = 0,防止重复计算

  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],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 struct xx{
 20     int fa;
 21     int bridge;
 22 }fa[N];
 23 vector<_cut> cut;//
 24 vector<int> poi;//lca
 25 
 26 void init(){
 27     for(int i = 0; i <= n; ++i){
 28         head[i] = -1;
 29         dfn[i] = 0;
 30     }
 31     cut.clear();
 32     scc = tim = tot = 0;
 33 }
 34 
 35 inline void add(int u,int v){
 36     e[tot].to = v;
 37     e[tot].nxt = head[u];
 38     head[u] = tot++;
 39 }
 40 
 41 void tarjan(int now,int pre){
 42     dfn[now] = low[now] = ++tim;
 43     s[top++] = now;
 44 
 45     int to,pre_cnt = 0;
 46     for(int o = head[now]; ~o; o = e[o].nxt){
 47         to = e[o].to;
 48         if(to == pre && pre_cnt == 0) { pre_cnt = 1; continue; }
 49         if(!dfn[to]){
 50             tarjan(to,now);
 51             low[now] = min(low[now],low[to]);
 52             if(dfn[now] < low[to]) cut.pb(_cut{now,to});
 53         }
 54         else if(low[now] > dfn[to]) low[now] = dfn[to];
 55     }
 56 
 57     if(dfn[now] == low[now]){
 58         int p;
 59         ++scc;
 60         boss[scc] = now;//记录该scc的源点
 61         do{
 62             p = s[--top];
 63             scc_no[p] = scc;
 64         }while(now != p);
 65     }
 66 }
 67 //得到源点函数
 68 inline int _boss(int x){
 69     return boss[scc_no[x]];
 70 }
 71 //重建图   boss进行并查集
 72 void rebuild(){
 73     ans = cut.size();
 74     int x,y;
 75     for(int i = 0; i < ans; ++i){
 76         x = _boss(cut[i].x);
 77         y = _boss(cut[i].y);
 78         //dfn上小,下大的树
 79         if(dfn[x] > dfn[y]) swap(x,y);
 80         fa[y].fa = x;
 81         fa[y].bridge = 1;
 82     }
 83 }
 84 
 85 void lca(int x,int y){
 86     int fax = _boss(x);
 87     int fay = _boss(y);
 88     //if(dfn[fax] == dfn[y]) return;
 89 
 90    // poi.pb(fax); poi.pb(fay);
 91     while(dfn[fax] != dfn[fay]){
 92         while(dfn[fax] > dfn[fay]){
 93             if(fa[fax].bridge){
 94                 --ans;
 95                 fa[fax].bridge = 0;
 96             }
 97             fax = fa[fax].fa;
 98         }
 99         while(dfn[fax] < dfn[fay]){
100             if(fa[fay].bridge){
101                 --ans;
102                 fa[fay].bridge = 0;
103             }
104             fay = fa[fay].fa;
105         }
106     }
107 
108 }
109 
110 int main(){
111 
112     int _case = 0;
113     while(~scanf("%d%d",&n,&m) && (n+m)){
114         init();
115         int u,v;
116         for(int i = 0; i < m; ++i){
117             scanf("%d%d",&u,&v);
118             add(u,v); add(v,u);
119         }
120 
121         tarjan(1,1);
122         rebuild();
123 
124         int q;
125         scanf("%d",&q);
126         printf("Case %d:\n",++_case);
127         while(q--){
128             scanf("%d%d",&u,&v);
129             lca(u,v);
130             printf("%d\n",ans);
131         }
132     }
133 
134 
135 
136     return 0;
137 }

 

posted @ 2020-01-14 13:24  SummerMingQAQ  阅读(277)  评论(0编辑  收藏  举报