http://poj.org/problem?id=3694 /* 题意:给出一幅图,里面有桥,给出Q个操作每个操作会添加一条边,问每次操作后图中桥的个数 每次求桥会太慢 考虑一下dfs树,树边肯定是桥,然后每连上x,y,就会形成一个环,这个环内的边就全部都不是割边 所以只要找到x,y的lca,把这个路径上的桥标记为否即可 */ #include<iostream> using namespace std; #define MAXN 100001 struct node { int v, next; }edge[10*MAXN]; int dfn[MAXN], low[MAXN];//深度优先搜索的次序,节点能回溯到最小顶点序号 int head[MAXN]; int vi[MAXN], fa[MAXN]; int cut[MAXN], bridge[MAXN]; int alloc, n, m, bridgenum; int index; inline int min(int a, int b) { return a<b?a:b; } inline int max(int a, int b) { return a>b?a:b; } void add(int a, int b)//建图 { alloc++; edge[alloc].v = b; edge[alloc].next = head[a]; head[a] = alloc; } void dfs(int u)//找桥的过程 { int son; vi[u] = 1; dfn[u] = low[u] = index++; bool flag = true; for(son=head[u]; son; son = edge[son].next) { int v = edge[son].v; if(v == fa[u] && flag) { flag = false; continue; } if(vi[v] == 1) { low[u] = min(low[u], dfn[v]); } else if(vi[v] == 0) { fa[v] = u; dfs(v); low[u] = min(low[u], low[v]); if(low[v] > dfn[u])//桥 { bridge[v] = 1; bridgenum++; } } } vi[u] = 2; } void lca(int x, int y) { if(dfn[x] < dfn[y]) swap(x, y); while(dfn[x] > dfn[y]) { if(bridge[x]) { bridge[x] = 0; bridgenum--; } x = fa[x]; } while(x != y) { if(bridge[x]) { bridge[x] = 0; bridgenum--; } if(bridge[y]) { bridge[y] = 0; bridgenum--; } x = fa[x]; y = fa[y]; } } int main() { // freopen("in.txt", "r", stdin); int a, b, t=1; while(scanf("%d %d", &n, &m) != EOF && n) { alloc = 0; memset(head, 0, sizeof(head)); while(m--) { scanf("%d %d", &a, &b); add(a, b); add(b, a); } memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(vi, 0, sizeof(vi)); memset(fa, 0, sizeof(fa)); memset(bridge, 0, sizeof(bridge)); bridgenum = 0; fa[1] = 1; index = 0; dfs(1); printf("Case %d:/n", t++); scanf("%d", &m); while(m--) { scanf("%d %d", &a, &b); lca(a, b); printf("%d/n", bridgenum); } puts(""); } return 0; }