Tarjan+LCA
Tarjan缩点之后的图是一颗树,树上所有的边都是桥,在树上连边,两端点之间所有的边就是要减去的桥。LCA能在log的时间复杂度记录树上两端点路径上的边。
因为一个子节点只有一条边连向自己的父节点,记录边可以直接记录子节点。
#pragma GCC optimize(2)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
using namespace std;
typedef long long ll;
const int Maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
const int Mod = 1e9+7;
struct Edge {
int v, next;
} edge[Maxn<<2], sedge[Maxn<<2];
int h[Maxn], edge_cnt, sh[Maxn], sedge_cnt;
int scc, Stack[Maxn], Top, indx;
int dfn[Maxn], low[Maxn], num[Maxn], pre[Maxn], deep[Maxn];
bool vis[Maxn];
void add(int u, int v) {
edge[edge_cnt].v = v;
edge[edge_cnt].next = h[u];
h[u] = edge_cnt++;
edge[edge_cnt].v = u;
edge[edge_cnt].next = h[v];
h[v] = edge_cnt++;
}
void sadd(int u, int v) {
sedge[sedge_cnt].v = v;
sedge[sedge_cnt].next = sh[u];
sh[u] = sedge_cnt++;
sedge[sedge_cnt].v = u;
sedge[sedge_cnt].next = sh[v];
sh[v] = sedge_cnt++;
}
void dfs(int u, int fa) {
dfn[u] = low[u] = ++indx;
Stack[Top++] = u;
bool ok = false;
for(int i = h[u]; i != -1; i = edge[i].next) {
Edge e = edge[i];
if(e.v == fa && !ok) {
ok = true; continue;
}
if(!dfn[e.v]) {
dfs(e.v, u);
low[u] = min(low[u], low[e.v]);
} else if(e.v != fa || ok) low[u] = min(low[u], dfn[e.v]);
}
if(dfn[u] == low[u]) {
scc++;
int v;
do {
v = Stack[--Top];
num[v] = scc;
} while(u != v);
}
}
void num_dfs(int u, int fa, int step) {
pre[u] = fa; deep[u] = step; vis[u] = true;
for(int i = sh[u]; i != -1; i = sedge[i].next) {
Edge e = sedge[i];
if(e.v == fa || vis[e.v]) continue;
num_dfs(e.v, u, step+1);
}
}
int main(void)
{
int n, m, cas = 0;
while(scanf("%d%d", &n, &m) != EOF) {
if(!n && !m) break;
for(int i = 0; i <= n; ++i) {
h[i] = num[i] = -1;
dfn[i] = low[i] = 0;
}
edge_cnt = 0;
int u, v;
for(int i = 0; i < m; ++i) {
scanf("%d%d", &u, &v);
add(u, v);
}
scc = Top = indx = 0;
dfs(1, -1);
for(int i = 0; i <= scc; ++i) {
sh[i] = -1; deep[i] = 0;
}
sedge_cnt = 0;
for(int i = 1; i <= n; ++i) {
for(int j = h[i]; j != -1; j = edge[j].next) {
Edge e = edge[j];
if(num[i] == num[e.v]) continue;
sadd(num[i], num[e.v]);
}
}
for(int i = 1; i <= scc; ++i) vis[i] = false;
num_dfs(1, -1, 1);
int Q, ans = scc-1;
scanf("%d", &Q);
printf("Case %d:\n", ++cas);
for(int i = 1; i <= scc; ++i) vis[i] = false;
while(Q--) {
scanf("%d%d", &u, &v);
int cnt = 0;
u = num[u]; v = num[v];
while(deep[u] > deep[v]) {
if(!vis[u]) {
vis[u] = true; cnt++;
}
u = pre[u];
}
while(deep[u] < deep[v]) {
if(!vis[v]) {
vis[v] = true; cnt++;
}
v = pre[v];
}
while(u != v) {
if(!vis[u]) {
vis[u] = true; cnt++;
}
if(!vis[v]) {
vis[v] = true; cnt++;
}
u = pre[u]; v = pre[v];
}
ans -= cnt;
printf("%d\n", ans);
}
puts("");
}
return 0;
}
浙公网安备 33010602011771号