博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[bzoj1787][Ahoi2008]Meet 紧急集合
阅读量:5908 次
发布时间:2019-06-19

本文共 2355 字,大约阅读时间需要 7 分钟。

题目大意:给你一棵树,和$3$个节点,要你找到树上的一个点,使得三个点到这个点的距离和最小,并输出个距离

题解:令三个点为$a,b,c$,$i,j$两点的$lca$为$lca_{i,j}$,第$i$个点的深度为$depth_i$,$i,j$两点之间的距离为$d_{i,j}$。所以会发现$lca_{a,b},lca_{b,c},lca_{a,c}$中至少有两个是相同的。
假设$lca_{a,b}==lca_{a,c}$:
$\therefore lca_{a,b,c}==lca_{a,b}==lca_{a,c}$
$$
\begin{align*}
ans&=d_{b,c}+d_{lca_{b,c},a}\\
&=d_{b,lca_{b,c}}+d_{lca_{b,c},c}+d_{lca_{b,c},lca_{a,b,c}}+d_{lca_{a,b,c},a}\\
&=depth_b+depth_c-2 \cdot depth_{lca_{b,c}}+depth_{lca_{b,c}}+depth_a-2\cdot depth_{lca_{a,b}}\\
&=depth_a+depth_b+depth_c+depth_{lca_{b,c}}-2\cdot depth_{lca_{a,b}}
\end{align*}
$$
再常规化:
$$
ans=depth_a+depth_b+depth_c+depth+\max\{depth_{lca_{a,b}},depth_{lca_{a,c}},depth_{lca_{b,c}}\}-2\cdot\min\{depth_{lca_{a,b}},depth_{lca_{a,c}},depth_{lca_{b,c}}\}
$$
卡点:倍增求$LCA$时$for$循环未循环到$1$
C++ Code:

#include 
#define maxn 500010#define lb(x) (x & -x)using namespace std;int n, m;inline void swap(int &a, int &b) {a ^= b ^= a ^= b;}int head[maxn], cnt;struct Edge { int to, nxt;} e[maxn << 1];void addE(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;}int dad[maxn][19], dep[maxn];void dfs(int rt) { for (int i = head[rt]; i; i = e[i].nxt) { int v = e[i].to; if (v != dad[rt][0]) { dep[v] = dep[rt] + 1; dad[v][0] = rt; dfs(v); } }}void init() { for (int i = 1; i < 19; i++) { for (int j = 1; j <= n; j++) { dad[j][i] = dad[dad[j][i - 1]][i - 1]; } }}int LCA(int x, int y) { if (x == y) return x; if (dep[x] < dep[y]) swap(x, y); for (int t = dep[x] - dep[y]; t; t &= t - 1) x = dad[x][__builtin_ctz(lb(t))]; if (x == y) return x; for (int i = 18; ~i; i--) if (dad[x][i] != dad[y][i]) x = dad[x][i], y = dad[y][i]; return dad[x][0];}int main() { scanf("%d%d", &n, &m); for (int i = 1; i < n; i++) { int a, b; scanf("%d%d", &a, &b); addE(a, b); addE(b, a); } dep[1] = 1; dfs(1); init(); while (m --> 0) { int a, b, c, ans = 0; scanf("%d%d%d", &a, &b, &c); int lca_ab = LCA(a, b), lca_ac = LCA(a, c), lca_bc = LCA(b, c); printf("%d ", lca_ab ^ lca_ac ^ lca_bc); if (lca_ab == lca_ac) ans = dep[b] + dep[c] - dep[lca_bc] + dep[a] - (dep[lca_ac] << 1); else { if (lca_bc == lca_ab) ans = dep[a] + dep[c] - dep[lca_ac] + dep[b] - (dep[lca_ab] << 1); else ans = dep[a] + dep[b] - dep[lca_ab] + dep[c] - (dep[lca_ac] << 1); } printf("%d\n", ans); } return 0;}

 

转载于:https://www.cnblogs.com/Memory-of-winter/p/9513179.html

你可能感兴趣的文章
springcloud入门之断路器Hystrix(四)
查看>>
凭借UGC壮大的马蜂窝,亦是喜忧参半
查看>>
零基础学习 Python 之细说类属性 & 实例
查看>>
JavaScript设计模式与开发实践笔记
查看>>
wx小程序(3) - 自定义组件及参数传输
查看>>
数据请求+
查看>>
Quiz - 回顾
查看>>
如何合理的规划jvm性能调优
查看>>
从地址字符串获取省市区信息
查看>>
莫比乌斯反演初步与实际应用
查看>>
javascript-高级用法
查看>>
409. Longest Palindrome
查看>>
大话javascript 1期:作用域和作用域链
查看>>
软件开发学习的5大技巧,你知道吗?
查看>>
eosjs 文档(JSON-RPC)
查看>>
前嗅ForeSpider教程:通过链接列表采集正文数据(翻页)
查看>>
Python 基础起步 (四) 变量是什么东西 ?
查看>>
技术分享:阿里巴巴Dubbo实现的源码分析
查看>>
TiDB 助力东南亚领先电商 Shopee 业务升级
查看>>
神级命令awk之30分钟速成必看
查看>>