zoukankan      html  css  js  c++  java
  • 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:
    ", cas ++);
    168         while(q --){
    169             int a, b;
    170             scanf("%d%d", &a, &b);
    171             printf("%d
    ", graph.getAns(a, b));
    172         }
    173         putchar('
    ');
    174     }
    175     return 0;
    176 }
  • 相关阅读:
    HDU 2188.悼念512汶川大地震遇难同胞——选拔志愿者-巴什博奕
    hdu 4217 Data Structure? 树状数组求第K小
    hdu 5137 How Many Maos Does the Guanxi Worth 最短路 spfa
    Codeforces Round #375 (Div. 2) C. Polycarp at the Radio 贪心
    Codeforces Round #375 (Div. 2) D. Lakes in Berland dfs
    hiho 1325 : 平衡树·Treap
    bzoj 2656 [Zjoi2012]数列(sequence) 递推+高精度
    Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) C. Destroying Array
    Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) D. Generating Sets 贪心+优先队列
    Codeforces Round #374 (Div. 2) A , B , C 水,水,拓扑dp
  • 原文地址:https://www.cnblogs.com/DarkScoCu/p/10581313.html
Copyright © 2011-2022 走看看