Tarjan 割边+LCA+并查集优化(缩点)
// poj 3694
// 题意: 给一个N个点M条边所有点联通的无向图,问 Q此询问,每次增加一条u->v的无向边,输出每次增加后桥的数量
// N(1≤N≤100000) M(N-1≤M≤200000) Q(1≤Q≤1000)
// Time Limi:5000ms
// 割边+LCA 672ms(非并查集优化)
1 #include<cstdio> 2 #include<algorithm> 3 #include<map> 4 #define rep(i, n) for(int i=0;i!=n;++i) 5 #define rep1(i, n) for(int i=1;i<=n;++i) 6 using namespace std; 7 8 inline int read() { 9 char c=getchar();int x=0,f=1; 10 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 11 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 12 return x*f; 13 } 14 // -------------------------------------------- 15 const int MAXN = 100000+5; 16 const int MAXM = 402000+5; 17 18 int num; 19 int head[MAXN]; 20 struct node { 21 int v, next; 22 } edge[MAXM]; 23 24 inline void add(int x, int y) { 25 edge[num].v = y; 26 edge[num].next = head[x]; 27 head[x] = num++; 28 } 29 30 int n, m, q; 31 int cnt, ans; 32 int dfn[MAXN], low[MAXN], pre[MAXN], deep[MAXN]; 33 bool bridge[MAXN]; 34 35 void Tarjan(int cur, int fa) { 36 dfn[cur] = low[cur] = ++cnt; 37 for(int i = head[cur]; i != -1; i = edge[i].next) { 38 int v = edge[i].v; 39 if(!dfn[v]) { 40 deep[v] = deep[cur] + 1; 41 pre[v] = cur; 42 Tarjan(v, cur); 43 low[cur] = min(low[cur], low[v]); 44 if(low[v] > dfn[cur]) bridge[v] = true, ++ans;// u->v是割边 用dridge[v]记录 45 } 46 else if(v != fa) low[cur] = min(low[cur], dfn[v]);// u!=fa 去重边 47 } 48 } 49 50 int LCA(int x, int y) {// (大致思想)LCA的过程中减去x->Lca(x,y)->y中的桥 51 if(deep[x] < deep[y]) swap(x, y); 52 while(deep[x] != deep[y]) { 53 if(bridge[x]) --ans, bridge[x] = false; 54 x = pre[x]; 55 } 56 while(x != y) { 57 if(bridge[x]) --ans, bridge[x] = false; 58 if(bridge[y]) --ans, bridge[y] = false; 59 x = pre[x]; y = pre[y]; 60 } 61 return ans; 62 } 63 64 void solve(int qaq) { 65 cnt = ans = 0; 66 rep1(i, n) bridge[i] = false; 67 rep1(i, n) dfn[i] = 0; 68 deep[1] = 1; 69 Tarjan(1, 0); 70 printf("Case %d:\n", qaq); 71 q = read(); 72 int x, y; 73 rep(i, q) { 74 x = read(); y = read(); 75 printf("%d\n", LCA(x, y)); 76 } 77 printf("\n"); 78 } 79 80 int main() { 81 int qaq = 1; 82 while(scanf("%d%d", &n, &m) == 2 && n) { 83 num = 0; 84 rep1(i, n) head[i] = -1; 85 int x, y; 86 rep(i, m) { 87 x = read(); y = read(); 88 add(x, y); add(y, x); 89 } 90 solve(qaq++); 91 } 92 return 0; 93 }
// 上述代码 并查集优化后 266ms(数据量小 不优化也挺快)
1 #include<cstdio> 2 #include<algorithm> 3 #include<map> 4 #define rep(i, n) for(int i=0;i!=n;++i) 5 #define rep1(i, n) for(int i=1;i<=n;++i) 6 using namespace std; 7 8 inline int read() { 9 char c=getchar();int x=0,f=1; 10 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 11 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 12 return x*f; 13 } 14 // -------------------------------------------- 15 const int MAXN = 100000+5; 16 const int MAXM = 402000+5; 17 18 int num; 19 int head[MAXN]; 20 struct node { 21 int v, next; 22 } edge[MAXM]; 23 24 inline void add(int x, int y) { 25 edge[num].v = y; 26 edge[num].next = head[x]; 27 head[x] = num++; 28 } 29 30 int n, m, q; 31 int cnt, ans; 32 int dfn[MAXN], low[MAXN], pre[MAXN]; 33 int fa[MAXN]; 34 35 inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } 36 37 inline void join(int x, int y) { 38 int xf = find(x), yf = find(y); 39 if(xf != yf) fa[xf] = yf; 40 } 41 42 void Tarjan(int cur, int prv) { 43 dfn[cur] = low[cur] = ++cnt; 44 for(int i = head[cur]; i != -1; i = edge[i].next) { 45 int v = edge[i].v; 46 if(!dfn[v]) { 47 pre[v] = cur; 48 Tarjan(v, cur); 49 low[cur] = min(low[cur], low[v]); 50 if(low[v] > dfn[cur]) ++ans; 51 else join(cur, v); 52 } 53 else if(v != prv) low[cur] = min(low[cur], dfn[v]); 54 } 55 } 56 57 inline void fn(int x) { 58 int xf = find(x), yf = find(pre[x]); 59 if(xf != yf) fa[xf] = yf, --ans;// 与父节点不在同一缩点中 60 } 61 62 void LCA(int x, int y) { 63 if(dfn[x] < dfn[y]) swap(x, y);// 可以用deep[] 但是用dfn[]也行 思考🤔 64 while(dfn[x] > dfn[y]) { 65 fn(x); 66 x = pre[x]; 67 } 68 while(x != y) { 69 fn(y); 70 y = pre[y]; 71 } 72 } 73 74 void solve(int qaq) { 75 cnt = ans = 0; 76 rep1(i, n) dfn[i] = 0, fa[i] = i; 77 Tarjan(1, 0); 78 printf("Case %d:\n", qaq); 79 q = read(); 80 int x, y; 81 rep(i, q) { 82 x = read(); y = read(); 83 if(find(x) != find(y)) LCA(x, y);// x和y 在同一缩点中 没有桥 84 printf("%d\n", ans); 85 } 86 printf("\n"); 87 } 88 89 int main() { 90 int qaq = 1; 91 while(scanf("%d%d", &n, &m) == 2 && n) { 92 num = 0; 93 rep1(i, n) head[i] = -1; 94 int x, y; 95 rep(i, m) { 96 x = read(); y = read(); 97 add(x, y); add(y, x); 98 } 99 solve(qaq++); 100 } 101 return 0; 102 }