poj 3694 Network : o(n) tarjan + O(n) lca + O(m) 维护 总复杂度 O(m*q)

  1 /**
  2 problem: http://poj.org/problem?id=3694
  3 
  4 问每加一条边后剩下多少桥
  5 因为是无向图,所以使用tarjan缩点后会成一棵树并维护pre数组
  6 在树上连一条边(a,b)减少的桥数就是
  7 a点到a点和b点的最近公共祖先(lca)的所有边+b点到a点和b点的最近公共祖先的所有边
  8 在算桥的同时将这些点缩成一个点
  9 即每个点color = 最近公共祖先color
 10 同时维护pre数组 每个点的pre = 最近公共祖先的pre 即可
 11 **/
 12 #include<stdio.h>
 13 #include<stack>
 14 #include<queue>
 15 #include<algorithm>
 16 using namespace std;
 17 
 18 const int MAXN = 100005;
 19 const int MAXM = 555555;
 20 
 21 class Graphics{
 22 private:
 23     struct Edge{
 24         int to, next;
 25         bool bridge;
 26     }edge[MAXM];
 27     struct Point{
 28         int dfn, low, color;
 29     }point[MAXN];
 30     int first[MAXN], pre[MAXN], sign, sumOfPoint, dfnNum, colorNum, bridge;
 31     bool vis[MAXN];
 32     stack<int> stk;
 33     queue<int> bfs;
 34     void tarjan(int u, int preEdge = -1){
 35         point[u].low = dfnNum;
 36         point[u].dfn = dfnNum ++;
 37         vis[u] = true;
 38         stk.push(u);
 39         for(int i = first[u]; i != -1; i = edge[i].next){
 40             int to = edge[i].to;
 41             if((i^1) == preEdge) continue;
 42             if(!point[to].dfn){
 43                 pre[to] = u; ///如果下一个点没被访问过则更新一下下个点的pre
 44                 tarjan(to, i);
 45                 point[u].low = min(point[u].low, point[to].low);
 46                 if(point[to].low > point[u].dfn){
 47                     edge[i].bridge = true;
 48                     edge[i^1].bridge = true;
 49                     bridge ++;
 50                 }
 51             }else if(vis[to]){
 52                 point[u].low = min(point[to].dfn, point[u].low);
 53             }
 54         }
 55         if(point[u].dfn == point[u].low){
 56             vis[u] = false;
 57             point[u].color = ++ colorNum;
 58             while(stk.top() != u){
 59                 pre[stk.top()] = pre[u]; ///缩点时,该环中的所有点pre等于时间戳最小点的pre
 60                 point[stk.top()].color = colorNum;
 61                 vis[stk.top()] = false;
 62                 stk.pop();
 63             }
 64             stk.pop();
 65         }
 66     }
 67 public:
 68     void clear(int n){
 69         sumOfPoint = n;
 70         for(int i = 1; i <= n; i ++){
 71             first[i] = -1;
 72             pre[i] = -1;
 73             vis[i] = 0;
 74             point[i].dfn = 0;
 75         }
 76         sign = colorNum = bridge = 0;
 77         dfnNum = 1;
 78         while(!stk.empty()) stk.pop();
 79     }
 80     void addEdgeOneWay(int u, int v){
 81         edge[sign].to = v;
 82         edge[sign].next = first[u];
 83         edge[sign].bridge = false;
 84         first[u] = sign ++;
 85     }
 86     void addEdgeTwoWay(int u, int v){
 87         addEdgeOneWay(u, v);
 88         addEdgeOneWay(v, u);
 89     }
 90     void tarjanAllPoint(){
 91         for(int i = 1; i <= sumOfPoint; i ++){
 92             if(!point[i].dfn)
 93                 tarjan(i);
 94         }
 95     }
 96     int getAns(int a, int b){
 97         for(int i = 1; i <= colorNum; i ++){
 98             vis[i] = false;
 99         }
100         vis[point[a].color] = true;
101         vis[point[b].color] = true;
102         int lca, lcacolor, ta = a, tb = b;
103         while(true){
104             if(ta != -1) ta = pre[ta];
105             if(tb != -1) tb = pre[tb];
106             if(vis[point[ta].color]){
107                 lcacolor = point[ta].color;
108                 lca = ta;
109                 break;
110             }
111             if(vis[point[tb].color]){
112                 lcacolor = point[tb].color;
113                 lca = tb;
114                 break;
115 
116             }
117             vis[point[ta].color] = true;
118             vis[point[tb].color] = true;
119         }
120         while(point[a].color != lcacolor){
121             for(int i = first[a]; i != -1; i = edge[i].next){
122                 int to = edge[i].to;
123                 if(to == pre[a] && edge[i].bridge){
124                     bridge --;
125                     edge[i].bridge = false;
126                     edge[i^1].bridge = false;
127                     break;
128                 }
129             }
130             point[a].color = lcacolor;
131             int tmp = pre[a];
132             pre[a] = pre[lca];
133             a = tmp;
134         }
135         while(point[b].color != lcacolor){
136             for(int i = first[b]; i != -1; i = edge[i].next){
137                 int to = edge[i].to;
138                 if(to == pre[b] && edge[i].bridge){
139                     bridge --;
140                     edge[i].bridge = false;
141                     edge[i^1].bridge = false;
142                     break;
143                 }
144             }
145             point[b].color = lcacolor;
146             int tmp = pre[b];
147             pre[b] = pre[lca];
148             b = tmp;
149         }
150         addEdgeTwoWay(a, b);
151         return bridge;
152     }
153 }graph;
154 
155 int main(){
156     int n, m, cas = 1;
157     while(scanf("%d%d", &n, &m) != EOF && m + n){
158         graph.clear(n);
159         while(m --){
160             int a, b;
161             scanf("%d%d", &a, &b);
162             graph.addEdgeTwoWay(a, b);
163         }
164         graph.tarjanAllPoint();
165         int q;
166         scanf("%d", &q);
167         printf("Case %d:\n", cas ++);
168         while(q --){
169             int a, b;
170             scanf("%d%d", &a, &b);
171             printf("%d\n", graph.getAns(a, b));
172         }
173         putchar('\n');
174     }
175     return 0;
176 }

 

posted @ 2019-03-22 22:03  DarkScoCu  阅读(226)  评论(0编辑  收藏  举报