题目链接(You can click it.)
题目含义:
有一张无向图,在其中添边。问每次添边之后,还剩多少桥。
思路:
首先,这个题解法不知这一种,这个简单一点,后续会补上其余的几个大同小异的解法(好题值得反复写)。
既然是求桥的数量,肯定离不开求桥了,求桥的数量可以在tarjan的过程中每遇到一个满足桥的判定式dfn < low,就ans++,最后ans就是初始桥的数量。或者也可以tarjan完毕后,缩点(dfs求连通块个数),最后的点数-1就是桥数。
题目中的图可以看作是一个无根树,人为的给树定一个根,将边打造为有向的,就可以得到一棵树,树上的点都是从父节点指向子节点。用一个mark数组,mark[i] 记录的是 i 节点指向父节点的边是否为桥。对于每一个输入进来的边 < u , v > <u,v> <u,v>,一定可以在树上找到一条边从 u u u到 v v v(题目中说了图是连通图,因此不存在两个点在树上找不到边),如果再增加一条边 < u , v > <u,v> <u,v>,那么原来从 u u u到 v v v路径上路过的桥边都失效了(这些边与新边形成了环),因此只需要找原路径上两点之间的边中的桥边的数量即可。
可以求两个点的 lca,让两个点同时向 lca 靠拢,路径上经过的边中的桥边即为所求。
在 tarjan 的过程中可以对每个点记录深度(毕竟tarjan也是对图进行了dfs),顺便标记每个点的父节点,再顺便求出来桥边的时候更新 mark 值。
这是参考一个大牛的解法,感觉这个解法是最简单的一个了QAQ
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define mem(a, b) memset(a, b, sizeof a)
const int N = 100100, M = 200100 * 2;
int head[N], to[M], nex[M], cnt;
int fa[N];
int dfn[N], low[N], num;
int d[N];
bool mark[N];
int ans;
void init(){
ans = 0; cnt = 1; mem(head, 0); mem(nex, 0); mem(dfn, 0);
mem(low, 0); num = 0; mem(d, 0); mem(fa, -1); mem(mark, 0);
}
void add(int a, int b){
++cnt;
to[cnt] = b;
nex[cnt] = head[a];
head[a] = cnt;
}
void tarjan(int x, int ind, int depth){
dfn[x] = low[x] = ++num;
d[x] = depth;
for (int i = head[x]; i; i = nex[i]){
int y = to[i];
if (!dfn[y]){
fa[y] = x;
tarjan(y, i, depth + 1);
low[x] = min(low[x], low[y]);
if (dfn[x] < low[y]){
mark[y] = 1;
ans++;
}
}
else if (ind != (i ^ 1))low[x] = min(low[x], dfn[y]);
}
}
int n, m, K;
void lca(int x, int y){
if (d[x] < d[y]){
x = x ^ y; y = x ^ y; x = x ^ y;
}
while (d[x] > d[y]){
if (mark[x]){
mark[x] = 0;
ans--;
}
x = fa[x];
}
while (x != y){
if (mark[x]){
mark[x] = 0;
ans--;
}
if (mark[y]){
mark[y] = 0;
ans--;
}
x = fa[x];
y = fa[y];
}
}
int main()
{
freopen("in.in", "r", stdin);
K = 1;
while (~scanf("%d %d", &n, &m) && n && m){
init();
while (m--){
int a, b;
scanf("%d %d", &a, &b);
add(a, b);
add(b, a);
}
tarjan(1, 0, 1);
int Q;
cin >> Q;
printf("Case %d:\n", K++);
while (Q--){
int x, y;
scanf("%d %d", &x, &y);
lca(x, y);
printf("%d\n", ans);
}
puts("");
}
return 0;
}