类型:图连通性
题目:http://poj.org/problem?id=3694
来源:2008 Asia Hefei Regional Contest Online by USTC
思路:Tarjan 算法搜索得到一颗树,记录每个节点的父节点及该节点的搜索深度,同时记录桥【通过记录末端点来记录桥--一一对应】
对于新添加的边,容易知道从这两个端点往上到其最近公共祖先路径上的桥会消除
通过端点不断向上删除桥【标记清除】
// poj 3694 Network
// wa wa wa ac 9616K 1000MS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
using namespace std;
#define clr(a,b) memset(a,b,sizeof(a))
#define MAXN 110000
#define MAXM 410000
bool vis[MAXN];
int F, R, q, bri_num, cnt, num;
int step[MAXN], father[MAXN], dep[MAXN], low[MAXN], head[MAXN], bridge[MAXN];
struct edge {
int v, nxt, id;
}e[MAXM];
void addedge(int u, int v, int id) {
e[cnt].v = v;
e[cnt].id = id;
e[cnt].nxt = head[u];
head[u] = cnt++;
}
void dfs(int fa, int u,int id, int d) {
father[u] = fa;
dep[u] = d;
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].v;
if(e[i].id != id) {
if(!vis[v]) {
vis[v] = true;
step[v] = low[v] = (++num);
dfs(u, v, e[i].id, d + 1);
low[u] = min(low[u], low[v]);
}
else
low[u] = min(low[u],step[v]);
if(low[v] > step[u])
bridge[v] = 1, bri_num++;
}
}
}
void LCA(int x, int y) {
if(dep[x] < dep[y])
swap(x, y);
while(dep[x] != dep[y]) {
if(bridge[x] == 1)
bridge[x] = 0, bri_num--;
x = father[x];
}
while(x != y) {
if(bridge[x] == 1)
bridge[x] = 0, bri_num--;
x = father[x];
if(bridge[y] == 1)
bridge[y] = 0, bri_num--;
y = father[y];
}
}
void init() {
int i, u, v;
clr(head, -1);
clr(vis, false);
clr(dep, 0);
clr(bridge, 0);
for(i = 0; i != R; ++i) {
scanf("%d %d", &u, &v);
addedge(u, v, i);
addedge(v, u, i);
}
step[1] = low[1] = num = 1;
cnt = bri_num = 0;
vis[1] = true;
}
int main() {
int cas = 1;
while(scanf("%d%d",&F,&R) == 2, F || R) {
init();
dfs(0, 1, 1, 0);
scanf("%d", &q);
int x, y;
printf("Case %d:\n", cas++);
for(int i = 0; i < q; ++i) {
scanf("%d %d", &x, &y);
LCA(x, y);
printf("%d\n", bri_num);
}
printf("\n");
}
return 0;
}