LCA小结
来源:互联网 发布:红米note3数据经常断网 编辑:程序博客网 时间:2024/06/04 08:43
LCA小结 A Summary for LCA
Ⅰ. LCA
- 什么是
LCA ?Lowest Common Ancestor , 指的是树上两点的最近公共祖先。
有了它, 我们可以高效地求解树上两点间的距离、最大权值边等信息。 LCA 的时间复杂度- 暴力
O(n+m+qn) - 倍增法
O(n+m+nlogn+qlogn) - 欧拉序列与RMQ
O(n+m+nlogn+q) - Tarjan离线算法
O(n+m+q) - 树链剖分
O(n+m+qlogn)
- 暴力
Ⅱ. LCA的代码模版
暴力与倍增法很好理解,对于欧拉序列与RMQ,Tarjan离线算法,其实都是利用了树的欧拉序列
欧拉序列即是树上两点路径经过点的序列,所以才能正确的求出lca(那个深度最小的点)
- 暴力
//brute forcevector<int> G[N];int fa[N], dep[N];void dfs(int u, int f, int d) { fa[u] = f; dep[u] = d; for(int i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if(v == f) continue; dfs(v, u, d + 1); }}void init() { dfs(root, -1, 0);}int lca(int u, int v) { if(dep[u] > dep[v]) swap(u, v); while(dep[v] > dep[u]) v = fa[v]; while(u != v) { u = fa[u]; v = fa[v]; } return u;}
- 倍增法
//doublingvector<int> G[N];const int LOG = 18;int p[LOG][N], dep[N];void dfs(int u, int f, int d) { dep[u] = d; p[0][u] = f; for(int i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if(v == f) continue; dfs(v, u, d + 1); }}void init() { dfs(root, -1, 0); for(int i = 0; i + 1 < LOG; ++i) for(int v = 1; v <= n; ++v) if(p[i][v] < 0) p[i + 1][v] = -1; else p[i + 1][v] = p[i][p[i][v]];}int lca(int u, int v) { if(dep[u] > dep[v]) swap(u, v); for(int i = 0; i < LOG; ++i) if(dep[v] - dep[u] >> i & 1) v = p[i][v]; if(u == v) return u; for(int i = LOG - 1; ~i; --i) { if(p[i][u] != p[i][v]) { u = p[i][u]; v = p[i][v]; } } return p[0][u];}
- 欧拉序列与RMQ
//Euler Sequence & RMQ(ST)int getMin(int x, int y) { return dep[x] < dep[y] ? x : y;}struct SparseTable { int dp[20][N << 1]; void init(int n) { for(int i = 1; i <= n; ++i) dp[0][i] = i; for(int i = 1; (1 << i) <= n; ++i) for(int j = 1; j + (1 << i) - 1 <= n; ++j) dp[i][j] = getMin(dp[i - 1][j], dp[i - 1][j + (1 << i - 1)]); } int RMQ(int l, int r) { int k = 31 - __builtin_clz(r - l + 1); return getMin(dp[k][l], dp[k][r - (1 << k) + 1]); }} st;vector<int> G[N];int vs[N << 1], dep[N << 1], first[N], dfsNum;void dfs(int u, int f, int d) { vs[++dfsNum] = u; dep[dfsNum] = d; first[u] = dfsNum; for(int i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if(v == f) continue; dfs(v, u, d + 1); vs[++dfsNum] = u; dep[dfsNum] = d; }}void init() { dfsNum = 0; dfs(root, -1, 0); st.init(2 * n - 1);}int lca(int u, int v) { if(first[u] > first[v]) swap(u, v); int idx = st.RMQ(first[u], first[v]); return vs[idx];}
- Tarjan离线算法
//Tarjan-lca & Disjoint Setstruct Query { int v, id;};vector<Query> Q[N];int ans[MAXQ], ancestor[N], vis[N];int find(int x) { return ancestor[x] = ancestor[x] == x ? x : find(ancestor[x]);}vector<int> G[N];void tarjan(int u) { vis[u] = true; ancestor[u] = u; for(int i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if(vis[v]) continue; tarjan(v); ancestor[v] = u; } for(int i = 0; i < Q[u].size(); ++i) { Query& q = Q[u][i]; if(vis[q.v]) ans[q.id] = find(q.v); }}
- 树链剖分
//HLD-lcaint lca(int u, int v) { int ret; while(true) { if(top[u] == top[v]) { ret = dep[u] < dep[v] ? u : v; break; } else if(dep[top[u]] > dep[top[v]]) u = fa[top[u]]; else v = fa[top[v]]; } return ret;}
Ⅲ. LCA的题目特点
利用倍增法dp的题目居多 嵌套数据结构动态查询 利用lca树上暴力
0 0
- LCA小结
- LCA小结
- LCA小结
- LCA小结。
- 【总结】LCA小结
- poj1330Nearest Common Ancestors(LCA小结)
- LCA 最近公共祖先 小结
- Tarjan离线算法求LCA小结
- LCA
- LCA
- lca
- LCA
- LCA
- lca
- LCA
- LCA
- LCA
- LCA
- delphi 判断大小端方法
- TextEntity.cs
- [s3c2416x移植u-boot-2015.10]如何在u-boot工程中取消对NorFlash的支持
- Seek the Name, Seek the Fame(KMP算法之next数组的深入理解实例)
- sl4j in project
- LCA小结
- Use the endorsed directory mechanism to place jaxb-api.jar(jaxb-api.jar、jaxws-api.jar与jdk1.6不兼容问题)
- DrawMenus.cs
- 怎么code review?
- DrawWidget.cs
- java中continue是什么意思?
- Leetcode Permutations II
- SQL Server管理及开发工具(Navicat for SQL Server)v11.2.13
- deploy 自己编写的 QT 程序 (window下打包程序)