hdu 6031 Innumerable Ancestors lca + 二分
来源:互联网 发布:js系列减速机加油标准 编辑:程序博客网 时间:2024/05/23 01:19
题目:
http://acm.hdu.edu.cn/showproblem.php?pid=6031
题意:
给定一个无向树形图,1为根,对于每次查询,给出两个集合,问两个集合中各选出一个点的最近公共祖先的深度最深为多少
思路:
用倍增求lca,然后二分枚举答案,求出第一个集合中的点在枚举的深度上的祖先,并标记这些祖先,然后求第二个集合中的点在枚举的深度上的祖先,检查两个集合在枚举深度上的祖先有没有重合,有重合就意味着在枚举深度上有lca
#include <bits/stdc++.h>using namespace std;const int N = 100000 + 10, INF = 0x3f3f3f3f;struct edge{ int to, next;}g[N*2];int cnt, head[N];int dep[N], dis[N], fat[N][20];int x[N], y[N];bool vis[N];void init(){ cnt = 0; memset(head, -1, sizeof head);}void add_edge(int v, int u){ g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;}void dfs(int v, int fa, int d){ dep[v] = d, fat[v][0] = fa; for(int i = head[v]; ~i; i = g[i].next) { int u = g[i].to; if(u == fa) continue; dfs(u, v, d+1); }}void lca_init(int n){ for(int j = 1; (1<<j) <= n; j++) for(int i = 1; i <= n; i++) fat[i][j] = fat[fat[i][j-1]][j-1];}int lca(int v, int u){ if(dep[v] < dep[u]) swap(v, u); int d = dep[v] - dep[u]; for(int i = 0; (d>>i) != 0; i++) if((d>>i) & 1) v = fat[v][i]; if(v == u) return v; for(int i = 18; i >= 0; i--) if(fat[v][i] != fat[u][i]) v = fat[v][i], u = fat[u][i]; return fat[v][0];}int query(int v, int d){ if(d < 0) return -1; if(d == 0) return v; for(int i = 0; (d>>i) != 0; i++) if((d>>i) & 1) v = fat[v][i]; return v;}bool check(int mid, int kx, int ky){ set<int> ste; for(int i = 1; i <= kx; i++) { int d = dep[x[i]] - mid; int v = query(x[i], d); if(v != -1) ste.insert(v); } for(int i = 1; i <= ky; i++) { int d = dep[y[i]] - mid; int v = query(y[i], d); if(ste.count(v)) return true; } return false;}int main(){ int n, m; while(~ scanf("%d%d", &n, &m)) { init(); int a, b; for(int i = 1; i <= n-1; i++) { scanf("%d%d", &a, &b); add_edge(a, b); add_edge(b, a); } dfs(1, 0, 1); lca_init(n); int kx, ky; for(int i = 1; i <= m; i++) { int mx = 0; scanf("%d", &kx); for(int j = 1; j <= kx; j++) scanf("%d", &x[j]), mx = max(mx, dep[x[j]]); scanf("%d", &ky); for(int j = 1; j <= ky; j++) scanf("%d", &y[j]); int l = 1, r = mx, ans; while(l <= r) { int mid = (l + r) >> 1; if(check(mid, kx, ky)) ans = mid, l = mid + 1; else r = mid - 1; } printf("%d\n", ans); } } return 0;}
我自己写了一个挺暴力的方法,首先把两个集合中的点分别按照深度从大到小排序,然后直接两重循环暴力,一个优化是如果当前点的深度小于已经求出的lca深度,就continue,然后这样就过了。。。
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N = 100010, INF = 0x3f3f3f3f;struct edge{ int to, next;}g[N*2];int cnt, head[N];int dis[N];int dp[20][N*2];int tot, dep[N*2], ord[N*2], fir[N];int x[N], y[N];void init(){ cnt = 0; memset(head, -1, sizeof head); tot = 0;}void add_edge(int v, int u){ g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;}void dfs(int v, int fa, int d){ ord[++tot] = v, dep[tot] = d, fir[v] = tot; for(int i = head[v]; i != -1; i = g[i].next) { int u = g[i].to; if(u == fa) continue; dfs(u, v, d + 1); ord[++tot] = v, dep[tot] = d; }}void ST(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 <= n - (1<<i) + 1; j++) dp[i][j] = dep[dp[i-1][j]] < dep[dp[i-1][j+(1<<(i-1))]] ? dp[i-1][j] : dp[i-1][j+(1<<(i-1))];}int RMQ(int l, int r){ int k = log(r - l + 1) / log(2.0); return dep[dp[k][l]] < dep[dp[k][r-(1<<k)+1]] ? dp[k][l] : dp[k][r-(1<<k)+1];}int LCA(int v, int u){ v = fir[v], u = fir[u]; if(v > u) swap(v, u); int res = RMQ(v, u); return ord[res];}int main(){ int n, m; while(~ scanf("%d%d", &n, &m)) { init(); int a, b; for(int i = 1; i <= n-1; i++) { scanf("%d%d", &a, &b); add_edge(a, b); add_edge(b, a); } dfs(1, 0, 1); ST(2*n - 1); int kx, ky; for(int i = 1; i <= m; i++) { scanf("%d", &kx); for(int j = 1; j <= kx; j++) scanf("%d", &x[j]); scanf("%d", &ky); for(int j = 1; j <= ky; j++) scanf("%d", &y[j]); sort(x + 1, x + 1 + kx, [](int a, int b){return dep[fir[a]] > dep[fir[b]];}); sort(y + 1, y + 1 + ky, [](int a, int b){return dep[fir[a]] > dep[fir[b]];}); int ans = 0; for(int j = 1; j <= kx; j++) { if(ans >= dep[fir[x[j]]]) continue; for(int k = 1; k <= ky; k++) { int lca = LCA(x[j], y[k]); ans = max(ans, dep[fir[lca]]); } } printf("%d\n", ans); } } return 0;}
阅读全文
0 0
- hdu 6031 Innumerable Ancestors(LCA+二分)
- hdu 6031 Innumerable Ancestors lca + 二分
- HDU 6031 Innumerable Ancestors【LCA】
- HDU 6031 Innumerable Ancestors (LCA)
- HDU 6031 Innumerable Ancestors(LCA,树链剖分)
- 【HDU6031】Innumerable Ancestors(二分+LCA)
- hdu 6031 Innumerable Ancestors
- HDU 6031 Innumerable Ancestors[树链剖分]
- 2017CCPC女生赛 hdu 6031 Innumerable Ancestors
- hdu6031 Innumerable Ancestors
- HDU6031 Innumerable Ancestors 倍增
- hdu 3830 二分+LCA
- HDU--3830[Checkers] LCA+二分
- HDU 3830 - Checkers(二分LCA)****
- hdu1470Closest Common Ancestors LCA
- Nearest Common Ancestors--LCA
- HDU6031[Innumerable Ancestor]--二分+倍增思想
- hdu-3830(奇妙的想法+LCA+二分)
- 字符串反转几种方法
- ThinkPHP中MVC代码范例
- 未“起飞”就倒闭?共享充电宝企业“乐电”逃之夭夭
- java 多态特性
- ADB命令抓取Android LogCat
- hdu 6031 Innumerable Ancestors lca + 二分
- ORM框架之GreenDao3.0使用详解(二)
- 矩阵计算
- padding实现居中
- Java 5种方法实现生产者消费者问题与2种方法实现读者写者问题
- 为啥我的Python这么慢 (一)
- se_lab4
- Centos7 在升级内核后,提示无法找到root等分区,导致系统无法启动
- linux单独安装oracle客户端及exp/imp工具配置&proc c_c++