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 }