POJ 3694 Network (算競進階習題)
阿新 • • 發佈:2019-05-08
pen %d its set work getchar() 超級 進階 true
邊雙聯通分量
數據很水,隨便亂搞。。
先把所有邊雙找出來,然後縮點。之後如果新加的邊在同一個邊雙,那橋的數量不變,如果在不同的邊雙,就一直往上跳到兩個點的LCA,通過的邊如果沒被標記,就標記一下,標記了就不再是橋了。。超級暴力!
#include <bits/stdc++.h> #define INF 0x3f3f3f3f #define full(a, b) memset(a, b, sizeof a) using namespace std; typedef long long ll; inline int lowbit(int x){ return x & (-x); } inline int read(){ int X = 0, w = 0; char ch = 0; while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); } while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar(); return w ? -X : X; } inline int gcd(int a, int b){ return a % b ? gcd(b, a % b) : b; } inline int lcm(int a, int b){ return a / gcd(a, b) * b; } template<typename T> inline T max(T x, T y, T z){ return max(max(x, y), z); } template<typename T> inline T min(T x, T y, T z){ return min(min(x, y), z); } template<typename A, typename B, typename C> inline A fpow(A x, B p, C lyd){ A ans = 1; for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd; return ans; } const int N = 200005; int n, m, cnt, k, tot, t, ans, head[N], dfn[N], low[N], c[N], first[N], cur, p[N][20], depth[N], from[N]; bool bri[N<<2], kills[N<<2]; struct Edge { int v, next; } edge[N<<2], e[N<<2]; void addEdge(int a, int b){ edge[cnt].v = b, edge[cnt].next = head[a], head[a] = cnt ++; } void link(int a, int b){ e[cur].v = b, e[cur].next = first[a], first[a] = cur ++; } void tarjan(int s, int pre){ dfn[s] = low[s] = ++k; for(int i = head[s]; i != -1; i = edge[i].next){ int u = edge[i].v; if(!dfn[u]){ tarjan(u, i); low[s] = min(low[s], low[u]); if(low[u] > dfn[s]) bri[i] = bri[i^1] = true; } else if(i != (pre^1)) low[s] = min(low[s], dfn[u]); } } void dfs(int s){ c[s] = tot; for(int i = head[s]; i != -1; i = edge[i].next){ int u = edge[i].v; if(c[u] || bri[i]) continue; dfs(u); } } void dfs(int s, int fa){ p[s][0] = fa, depth[s] = depth[fa] + 1; for(int i = 1; i <= t; i ++){ p[s][i] = p[p[s][i - 1]][i - 1]; } for(int i = first[s]; i != -1; i = e[i].next){ int u = e[i].v; if(u == fa) continue; from[u] = i; dfs(u, s); } } int lca(int x, int y){ if(depth[x] < depth[y]) swap(x, y); for(int i = t; i >= 0; i --){ if(depth[p[x][i]] >= depth[y]) x = p[x][i]; } if(x == y) return y; for(int i = t; i >= 0; i --){ if(p[x][i] == p[y][i]) continue; x = p[x][i], y = p[y][i]; } return p[y][0]; } void build(){ cnt = 2; k = tot = t = ans = cur = 0; full(head, -1), full(first, -1); full(dfn, 0), full(low, 0); full(c, 0), full(depth, 0); full(p, 0), full(from, 0); full(bri, false), full(kills, false); } int main(){ int _ = 0; n = read(), m = read(); while(n && m){ build(); for(int i = 0; i < m; i++){ int u = read(), v = read(); addEdge(u, v), addEdge(v, u); } for(int i = 1; i <= n; i++){ if(!dfn[i]) tarjan(i, 0); } for(int i = 1; i <= n; i++){ if(!c[i]) ++tot, dfs(i); } for(int i = 2; i < cnt; i += 2){ int u = edge[i^1].v, v = edge[i].v; if(c[u] != c[v]) link(c[u], c[v]), link(c[v], c[u]); if(bri[i]) ans++; } t = (int) (log(n) / log(2)) + 1; dfs(1, 0); int q = read(); printf("Case %d:\n", ++_); while(q--){ int u = read(), v = read(); if(c[u] == c[v]) printf("%d\n", ans); else{ int num = 0; int f = lca(c[u], c[v]); int tmp = c[u]; while(tmp != f){ if(!kills[from[tmp]]){ kills[from[tmp]] = kills[from[tmp]^1] = true; num++; } tmp = p[tmp][0]; } tmp = c[v]; while(tmp != f){ if(!kills[from[tmp]]){ kills[from[tmp]] = kills[from[tmp]^1] = true; num++; } tmp = p[tmp][0]; } ans -= num; printf("%d\n", ans); } } n = read(), m = read(); } return 0; }
POJ 3694 Network (算競進階習題)