大意略。
思路:开始的每加一次边就用Tarjan求一次桥边,这样肯定超时了。后来发现,只要在x->y之间连一条边的话,那么在x->y以及到它们的LCA之间形成了一个环,那么之间割边都不存在了。
求LCA的做法:把它们上升到同一个层次,然后一起往父亲节点走即可。
#include <iostream> #include <cstdlib> #include <cstdio> #include <string> #include <cstring> #include <cmath> #include <vector> #include <queue> #include <algorithm> #include <map> using namespace std; const int maxn = 100010; const int maxm = 200010*2; struct Edge { int u, v; int next; }edge[maxm]; int n, m; int cnt; int first[maxn]; int dfn[maxn], low[maxn], ins[maxn]; int top, scnt, tot; int bridge[maxn]; int p[maxn]; int num; void init() { cnt = 0; top = scnt = tot = 0; memset(first, -1, sizeof(first)); memset(ins, 0, sizeof(ins)); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(bridge, 0, sizeof(bridge)); for(int i = 0; i <= n; i++) p[i] = i; } void read_graph(int u, int v) { edge[cnt].v = v; edge[cnt].next = first[u], first[u] = cnt++; } void Tarjan(int u, int fa) { low[u] = dfn[u] = ++tot; bool repeat = 0; for(int e = first[u]; e != -1; e = edge[e].next) { int v = edge[e].v; if(v == fa && !repeat) { repeat = 1; continue; } if(!dfn[v]) { p[v] = u; Tarjan(v, u); low[u] = min(low[u], low[v]); if(dfn[u] < low[v]) { bridge[v] = 1; num++; } } else low[u] = min(low[u], dfn[v]); } } void LCA(int x, int y) { if(dfn[x] < dfn[y]) swap(x, y); /*while(dfn[x] > dfn[y]) { if(bridge[x]) { num--; bridge[x] = 0; } x = p[x]; }*/ while(x != y) { if(bridge[x]) { num--; bridge[x] = 0;} if(bridge[y]) { num--; bridge[y] = 0; } x = p[x]; y = p[y]; } } int main() { int times = 0; while(~scanf("%d%d", &n, &m) && (n || m)) { init(); while(m--) { int u, v; scanf("%d%d", &u, &v); read_graph(u, v), read_graph(v, u); } num = 0; Tarjan(1, -1); printf("Case %d:\n", ++times); int Q; scanf("%d", &Q); while(Q--) { int x, y; scanf("%d%d", &x, &y); LCA(x, y); printf("%d\n", num); } printf("\n"); } return 0; }