POJ 3694 (tarjan缩点+LCA+并查集)
好久没写过这么长的代码了,题解东哥讲了那么多,并查集优化还是很厉害的,赶快做做前几天碰到的相似的题。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 1e5 + 50, M = 2e5 + 50; 7 int head[N], ver[M * 2], Next[M * 2]; 8 int dfn[N], low[N], n, m, tot, num; 9 bool bridge[M * 2]; 10 11 void add(int x, int y) 12 { 13 ver[++tot] = y, Next[tot] = head[x], head[x] = tot; 14 } 15 void tarjan(int x, int in_edge) 16 { 17 dfn[x] = low[x] = ++num; 18 for(int i = head[x]; i; i = Next[i]) 19 { 20 int y = ver[i]; 21 if(!dfn[y]) 22 { 23 tarjan(y, i); ///节点 和 入边 24 low[x] = min(low[x], low[y]); 25 26 if(low[y] > dfn[x]) 27 { 28 bridge[i] = bridge[i ^ 1] = true; 29 } 30 } 31 else if(i != (in_edge ^ 1)) ///搜索树上的边 32 { 33 low[x] = min(low[x], dfn[y]); 34 } 35 } 36 } 37 int c[N], dcc; 38 void dfs(int x) 39 { 40 c[x] = dcc; 41 for(int i = head[x]; i; i = Next[i]) 42 { 43 int y = ver[i]; 44 if(c[y] || bridge[i]) continue; 45 dfs(y); 46 } 47 } 48 const int maxn = N; 49 ///加边 50 int cnt, h[maxn]; 51 struct edge 52 { 53 int to, pre, v; 54 } e[maxn << 1]; 55 void add(int from, int to, int v) 56 { 57 cnt++; 58 e[cnt].pre = h[from]; ///5-->3-->1-->0 59 e[cnt].to = to; 60 e[cnt].v = v; 61 h[from] = cnt; 62 } 63 ///LCA 64 int dist[maxn]; 65 int dep[maxn]; 66 int anc[maxn][33]; ///2分的父亲节点 67 void dfs(int u, int fa) 68 { 69 for(int i = h[u]; i; i = e[i].pre) 70 { 71 int v = e[i].to; 72 if(v == fa) continue; 73 dist[v] = dist[u] + e[i].v; 74 dep[v] = dep[u] + 1; 75 anc[v][0] = u; 76 dfs(v, u); 77 } 78 } 79 void LCA_init(int n) 80 { 81 for(int j = 1; (1 << j) < n; j++) 82 for(int i = 1; i <= n; i++) if(anc[i][j-1]) 83 anc[i][j] = anc[anc[i][j-1]][j-1]; 84 } 85 int LCA(int u, int v) 86 { 87 int log; 88 if(dep[u] < dep[v]) swap(u, v); 89 for(log = 0; (1 << log) < dep[u]; log++); 90 for(int i = log; i >= 0; i--) 91 if(dep[u] - (1 << i) >= dep[v]) u = anc[u][i]; 92 if(u == v) return u; 93 for(int i = log; i >= 0; i--) 94 if(anc[u][i] && anc[u][i] != anc[v][i]) 95 u = anc[u][i], v = anc[v][i]; 96 return anc[u][0]; 97 } 98 int fa[N]; 99 int Find(int x) 100 { 101 if(x == fa[x]) return x; 102 return fa[x] = Find(fa[x]); 103 } 104 int main() 105 { 106 int kase = 0; 107 while(scanf("%d %d", &n, &m) != EOF) 108 { 109 if(n == 0 && m == 0) break; 110 tot = 1, dcc = 0, cnt = 0; 111 for(int i = 1; i <= n; i++) head[i] = 0, dfn[i] = 0, low[i] = 0, c[i] = 0, h[i] = 0; 112 for(int i = 1; i <= m * 2 + 1; i++) ver[i] = 0, Next[i] = 0, bridge[i] = false; 113 for(int i = 1; i <= m; i++) 114 { 115 int x, y; scanf("%d %d", &x, &y); 116 add(x, y), add(y, x); 117 } 118 ///求桥 119 for(int i = 1; i <= n; i++) 120 { 121 if(!dfn[i]) tarjan(i, 0); 122 } 123 ///求边双连通分量 124 for(int i = 1; i <= n; i++) 125 { 126 if(!c[i]) 127 { 128 ++dcc; 129 dfs(i); 130 } 131 } 132 ///缩点 133 for(int i = 2; i <= tot; i++) 134 { 135 int x = ver[i ^ 1], y = ver[i]; 136 if(c[x] == c[y]) continue; 137 add(c[x], c[y], 1); 138 } 139 dfs(1, 0); 140 LCA_init(dcc); 141 ///并查集初始化 142 for(int i = 1; i <= dcc; i++) fa[i] = i; 143 int Q; scanf("%d", &Q); 144 int ans = dcc - 1; 145 printf("Case %d:\n", ++kase); 146 while(Q--) 147 { 148 int x, y; scanf("%d %d", &x, &y); 149 x = c[x], y = c[y]; 150 int p = LCA(x, y); 151 x = Find(x); 152 while(dep[x] > dep[p]) 153 { 154 fa[x] = anc[x][0]; 155 ans--; 156 x = Find(x); 157 } 158 y = Find(y); 159 while(dep[y] > dep[p]) 160 { 161 fa[y] = anc[y][0]; 162 ans--; 163 y = Find(y); 164 } 165 printf("%d\n", ans); 166 } 167 } 168 return 0; 169 }
转载于:https://www.cnblogs.com/wangwangyu/p/9682999.html
POJ 3694 (tarjan缩点+LCA+并查集)相关推荐
- 【割边缩点】解题报告:POJ - 3694 - Network(Tarjan割边缩点 + LCA + 并查集优化)
POJ - 3694 - Network 给定一张N个点M条边的无向连通图,然后执行Q次操作,每次向图中添加一条边,并且询问当前无向图中"桥"的数量.N≤105,M≤2∗105,Q ...
- POJ 3694 Network ★(边双连通分量+并查集缩点+LCA)
[题意]一个无向图可以有重边,下面q个操作,每次在两个点间连接一条有向边,每次连接后整个无向图还剩下多少桥(每次回答是在上一次连边的基础之上) [分析]好题,做完后涨了很多姿势~ 普通做法当然就是每加 ...
- POJ - 3694 Network(边双缩点+LCA+并查集优化)
题目链接:点击查看 题目大意:给出一个由n个点组成的无向图,现在有m次操作,每次操作都会向图中增加一条无向边,每次操作后询问当前图中有多少个桥 题目分析:题意很好理解,思路也很好想,就是代码量有点小多 ...
- POJ 3694Network(Tarjan边双联通分量 + 缩点 + LCA并查集维护)
[题意]: 有N个结点M条边的图,有Q次操作,每次操作在点x, y之间加一条边,加完E(x, y)后还有几个桥(割边),每次操作会累积,影响下一次操作. [思路]: 先用Tarjan求出一开始总的桥的 ...
- POJ 1703 Find them, Catch them(并查集高级应用)
POJ 1703 Find them, Catch them(并查集高级应用) 手动博客搬家:本文发表于20170805 21:25:49, 原地址https://blog.csdn.net/sunc ...
- POJ 1417 True Liars(路径压缩并查集+DP背包问题)
POJ 1417 True Liars(路径压缩并查集+DP背包问题) http://poj.org/problem?id=1417 题意: 给出p1+p2个人,其中p1个是好人,p2个是坏人.然后有 ...
- POJ 3694 Network(tarjan+lca+并查集)
题目 给定一张NNN个点MMM条边的无向连通图,然后执行QQQ次操作,每次向图中添加一条边,并且询问当前无向图中"桥"的数量. 题解 先求出图中所有的边双,然后缩点 令c[x],c ...
- POJ - 2513 Colored Sticks(字典树+并查集+欧拉回路)
题目链接:点击查看 题目大意:给出n个木棍,问若两两相连,最终能否构成一根长直木棍,相连的规则是两个木棍的相接端点的颜色需要保持相同 题目分析:关于这个题目,我们可以将每个木棍视为一条边,每个木棍的两 ...
- 51nod1743-雪之国度【最小生成树,LCA,并查集】
正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1743 题目大意 nnn个点mmm条边的一张图,每次询问要求找出x,yx, ...
最新文章
- ICCV2021旷视研究院入选9篇paper介绍(检测+点云+图像配准等)
- ANSYS——后处理中单元表(ELEMENT table)的作用、创建、使用
- 动态后台获取_后台管理系统的权限以及vue处理权限的思路
- Java ArrayList set()方法与示例
- 2018 A Sparse Topic Model for Extracting Aspect-Specific Summaries from Online Reviews 稀疏主题模型学习笔记
- substance design graph 不显示_每天1分钟背单词 词根 graph
- 封闭期5年的基金属于什么基金?
- SELECT INTO 和 replace into SELECT
- vc mysql ado blob_在VC下采用ADO实现BLOB(Binary)数据的存储,读取,修改,删除。...
- 组合数学1--组合数学简介
- 算法设计技巧与分析 答案整理
- 手机连上蓝牙耳机没有声音
- navigator 导航标签
- 时空恋旅人 豆瓣影评
- 怎样判断计算机硬盘损坏,检测硬盘是否损坏的方法来了,这里有四种判断方法!...
- Thinkphp6 搭建一套商城(拼团、秒杀、优惠券)
- Halide:简化图像编程
- 1.1 OpenFlow 概述
- 隆重推荐:大明王朝1566
- 如何成为一个高效、快乐、健康的程序员