zoukankan      html  css  js  c++  java
  • POJ3694 Network

    Description

    给定$N$个点和 $M$条边的无向联通图, 有$Q$ 次操作, 连接两个点的边, 问每次操作后的图中有几个桥

    Solution

    首先Tarjan找出边双联通分量, 每个双联通分量缩成一个点, 就构成了一棵树, 每一条树边都是桥。

    执行连$u, v$ 边时, 用并查集跳到没有桥的深度最浅并且深度比$lca$深的点, 将它与父节点的并查集合并, 再接着跳。

    每跳一次, 桥的数量就减少$1$。

    另外感谢Iowa 神犇提醒我$cut$数组要开$M << 1$, 不是 $N << 1$, 拯救了$RE$崩溃的我呜呜

    Code

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #define rd read()
      5 using namespace std;
      6 
      7 const int N = 1e5 + 1e4;
      8 const int M = 2e5 + 1e4;
      9 
     10 int n, m, dfn[N], low[N], cnt; 
     11 int head[N], tot;
     12 int Head[N], Tot;
     13 int col[N], col_num, father[N], ans;
     14 int top[N], son[N], size[N], f[N], dep[N];
     15 int cut[M << 1];
     16 
     17 struct edge {
     18     int nxt, to;
     19 }E[M << 1], e[M << 1];
     20 
     21 int read() {
     22     int X = 0, p = 1; char c = getchar();
     23     for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1;
     24     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
     25     return X * p;
     26 }
     27 
     28 void add(int u, int v) {
     29     e[++tot].to = v;
     30     e[tot].nxt = head[u];
     31     head[u] = tot;
     32 }
     33 
     34 void Add(int u, int v) {
     35     E[++Tot].to = v;
     36     E[Tot].nxt = Head[u];
     37     Head[u] = Tot;
     38 }
     39 
     40 void dfs1(int u) {
     41     size[u] = 1;
     42     for(int i = Head[u]; i; i = E[i].nxt) {
     43         int nt = E[i].to;
     44         if(nt == f[u]) continue;
     45         f[nt] = u;
     46         dep[nt] = dep[u] + 1;
     47         dfs1(nt);
     48         size[u] += size[nt];
     49         if(size[nt] > size[son[u]]) son[u] = nt;
     50     }
     51 }
     52 
     53 void dfs2(int u) {
     54     if(!son[u]) return;
     55     top[son[u]] = top[u];
     56     dfs2(son[u]);
     57     for(int i = Head[u]; i; i = E[i].nxt) {
     58         int nt = E[i].to;
     59         if(nt == f[u] || nt == son[u]) continue;
     60         top[nt] = nt;
     61         dfs2(nt);
     62     }
     63 }
     64 
     65 int LCA(int x, int y) {
     66     for(; top[x] != top[y];) {
     67         if(dep[top[x]] < dep[top[y]]) swap(x, y);
     68         x = f[top[x]];
     69     }
     70     if(dep[x] < dep[y]) swap(x, y);
     71     return y;
     72 }
     73 
     74 int get(int x) {
     75     return father[x] == x? x : father[x] = get(father[x]);
     76 }
     77 
     78 void merg(int x, int y) {
     79     x = get(x); y = get(y);
     80     father[x] = y;
     81 }
     82 
     83 int ch(int x) {
     84     return ((x + 1) ^ 1) - 1;
     85 }
     86 
     87 void tarjan(int u, int pre) {
     88     dfn[u] = low[u] = ++cnt;
     89     for(int i = head[u]; i; i = e[i].nxt) {
     90         if(i == ch(pre)) continue; 
     91         int nt = e[i].to;
     92                 if(!dfn[nt]) {
     93                     tarjan(nt, i);
     94                     low[u] = min(low[u], low[nt]);
     95                     if(low[nt] > dfn[u]) {
     96                         cut[ch(i)] = cut[i] = 1;
     97                         ans++;
     98                     }
     99                 }
    100                 else low[u] = min(low[u], dfn[nt]);
    101     }
    102 }
    103 
    104 void dfs(int u) {
    105     col[u] = col_num;
    106     for(int i = head[u]; i; i = e[i].nxt) {
    107         int nt = e[i].to;
    108         if(col[nt] || cut[i]) continue;
    109         dfs(nt);
    110         //blo[col_num].push_back(nt);
    111     }
    112 }
    113 
    114 void work() {
    115     ans = Tot = tot = cnt = col_num = 0;
    116     memset(Head, 0, sizeof(Head));
    117     memset(head, 0, sizeof(head));
    118     memset(cut, 0, sizeof(cut));
    119     memset(dfn, 0, sizeof(dfn));
    120     memset(col, 0, sizeof(col));
    121     memset(son, 0, sizeof(son));
    122     memset(size, 0, sizeof(size));
    123     for(int i = 1; i <= m; ++i) {
    124         int u = rd, v = rd;
    125         add(u, v); add(v, u);
    126     }
    127     for(int i = 1; i <= n; ++i) if(!dfn[i]) tarjan(i, 0);
    128     for(int i = 1; i <= n; ++i) if(!col[i]) {
    129         ++col_num; dfs(i);
    130     }
    131     for(int i = 1; i <= tot; ++i) {
    132         int x = e[i].to, y = e[ch(i)].to;
    133         if(col[x] == col[y]) continue;
    134         Add(col[x], col[y]);
    135     }
    136     for(int i = 1; i <= col_num; ++i) father[i] = i;
    137     dfs1(1);
    138     top[1] = 1; dfs2(1);
    139     int T = rd;
    140     for(; T; T--) {
    141         int u = col[rd], v = col[rd], lca = LCA(u, v);
    142         u = get(u); v = get(v);
    143         while(dep[u] > dep[lca]) {
    144             merg(u, f[u]);
    145             u = get(u);
    146             ans --;
    147         }
    148         while(dep[v] > dep[lca]) {
    149             merg(v, f[v]);
    150             v = get(v);
    151             ans --;
    152         }
    153         printf("%d
    ", ans);
    154     }
    155 }
    156 
    157 int main()
    158 {
    159     for(int i = 1; ; ++i) {
    160         n = rd; m = rd;
    161         if(!n && !m) return 0;
    162         printf("Case %d:
    ", i);
    163         work();
    164         putchar('
    ');
    165     }
    166 }
    View Code
  • 相关阅读:
    洛谷 P1508 Likecloud-吃、吃、吃
    Codevs 1158 尼克的任务
    2017.10.6 国庆清北 D6T2 同余方程组
    2017.10.6 国庆清北 D6T1 排序
    2017.10.3 国庆清北 D3T3 解迷游戏
    2017.10.3 国庆清北 D3T2 公交车
    2017.10.3 国庆清北 D3T1 括号序列
    2017.10.4 国庆清北 D4T1 财富
    2017.10.7 国庆清北 D7T2 第k大区间
    2017.10.7 国庆清北 D7T1 计数
  • 原文地址:https://www.cnblogs.com/cychester/p/9626945.html
Copyright © 2011-2022 走看看