题目描述

这次也是很长的题面啊\(qwq\)

题目大意如下:

给定一棵\(N\)个节点的树以及\(M\)次询问,每次询问给出\(x,\ y,\ z\)三个节点,程序需要在树上找一个点\(p\)

使得\(c = dist(x,p)+dist(y,p)+dist(z,p)\)取最小值,每一次询问输出满足条件的\(p\)和此时的最小的\(c\)


基本思路

看到树上距离的题,很容易想到\(LCA\),但是此处有三个点,不能直接用\(LCA\),所以我们得绕一点弯...

考虑求出三个点两两之间的$LCA,\ $那么我们可以马上想到:

\[p \in \{ LCA(x,y),LCA(x,z),LCA(y,z)\}
\]

证明:

对于一条树上路径\((x, y)\),显然对于

\[\forall\ p \in (x,y), dist(x,p)+dist(p,y)=dist(x,y)
\]

所以该$\ p\ \(点并不会影响\)x,y\(的费用,所以我们应该尽可能使\)\ p\ \(点靠近\)\ z\ $点

此时需要分类讨论 :

  1. \(z \in (x,y) ,\)那么\(p=z\)
  2. \(z \notin (x,y),\)那么
    1. \(z \in SubTree(x)(\)或 \(z \in SubTre(y)),p=x(\)或\(p=y)\)
    2. \(z \notin SubTree(x)\)且\(z \notin SubTree(y), z=LCA(x,y)\)

是不是感觉好麻烦?其实我们完全没必要做这么多。\(qwq\)

因为\(x,y,z\)是有轮换性的,所以只需要用某两个点之间的\(LCA\)试着更新\(p\)点就好了,结论也就是这么出来的

(具体过程可以根据上面的分类讨论,自己yy一下,最好画一张图我才不会告诉你我不会用几何画板)


细节注意事项

计算树上路径时,一定不要直接用\(dep\)去减,跑得过样例但是会WA


参考代码

#include <cstdio>
#include <cstring>
#define rg register
const int MAXN = 500010;
inline int abs(int a) { return a < 0 ? -a : a; }
inline void swap(int& a, int& b) { int t = a; a = b; b = t; }
inline int read() {
int s = 0; bool f = false; char c = getchar();
while (c < '0' || c > '9') f |= (c == '-'), c = getchar();
while (c >= '0' && c <= '9') s = (s << 3) + (s << 1) + (c ^ 48), c = getchar();
return f ? -s : s;
}
int tot, head[MAXN], nxt[MAXN << 1], ver[MAXN << 1];
inline void Add_edge(int u, int v) { nxt[++tot] = head[u], head[u] = tot, ver[tot] = v; }
int dep[MAXN], f[MAXN][22];
inline void dfs(int u, int fa) {
dep[u] = dep[fa] + 1, f[u][0] = fa;
for (rg int i = 1; i <= 20; i++)
f[u][i] = f[f[u][i - 1]][i - 1];
for (rg int v, i = head[u]; i; i = nxt[i])
if(!dep[v = ver[i]]) dfs(v, u);
}
inline int LCA(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (rg int i = 20; ~i; --i) if (dep[f[x][i]] >= dep[y]) x = f[x][i];
if (x == y) return x;
for (rg int i = 20; ~i; --i) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int main() {
int n = read(), q = read();
for (rg int i = 1; i < n; i++) {
int u = read(), v = read();
Add_edge(u, v), Add_edge(v, u);
}
dfs(1, 0);
for (rg int i = 1; i <= q; i++) {
int x = read(), y = read(), z = read();
int pos, minn = 2147483647, c;
//根据轮换性(所以这三段都长得差不多...)
int lca1 = LCA(x, y);
c = dep[x] + dep[y] - 2 * dep[lca1];
int lcaz = LCA(lca1, z);
c += dep[lca1] + dep[z] - 2 * dep[lcaz];
if (minn > c) pos = lca1, minn = c; int lca2 = LCA(x, z);
c = dep[x] + dep[z] - 2 * dep[lca2];
int lcay = LCA(lca2, y);
c += dep[lca2] + dep[y] - 2 * dep[lcay];
if (minn > c) pos = lca2, minn = c; int lca3 = LCA(y, z);
c = dep[y] + dep[z] - 2 * dep[lca3];
int lcax = LCA(lca3, x);
c += dep[x] + dep[lca3] - 2 * dep[lcax];
if (minn > c) pos = lca3, minn = c; printf("%d %d\n", pos, minn);
}
return 0;
}

完结撒花\(qwq\)

「AHOI2008」紧急集合/聚会的更多相关文章

  1. 「AHOI2008」「LuoguP4281」紧急集合 / 聚会(LCA

    题目描述 欢乐岛上有个非常好玩的游戏,叫做“紧急集合”.在岛上分散有N个等待点,有N-1条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路从一个点到另一个点要 ...

  2. 【bzoj1787】&【bzoj1832】[Ahoi2008]Meet 紧急集合 & 聚会

    bzoj1787就是bzoj1832 bzoj1832 空间和时间少了一些... 求三个结点到一个结点距离之和最小的结点以及距离和 求出两两lca,其中有两个相同,答案则为另一个 感觉就是一大暴力.. ...

  3. P4281 [AHOI2008]紧急集合 / 聚会

    P4281 [AHOI2008]紧急集合 / 聚会 lca 题意:求3个点的lca,以及3个点与lca的距离之和. 性质:设点q1,q2,q3 两点之间的lca t1=lca(q1,q2) t2=lc ...

  4. [AHOI2008]紧急集合 / 聚会(LCA)

    [AHOI2008]紧急集合 / 聚会 题目描述 欢乐岛上有个非常好玩的游戏,叫做"紧急集合".在岛上分散有N个等待点,有N-1条道路连接着它们,每一条道路都连接某两个等待点,且通 ...

  5. bzoj1787[Ahoi2008]Meet 紧急集合&bzoj1832[AHOI2008]聚会

    bzoj1787[Ahoi2008]Meet 紧急集合 bzoj1832[AHOI2008]聚会 题意: 给个树,每次给三个点,求与这三个点距离最小的点. 题解: 倍增求出两两之间的LCA后,比较容易 ...

  6. bzoj 1787 [Ahoi2008]Meet 紧急集合(1832 [AHOI2008]聚会)

    1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1841  Solved: 857[Submit][ ...

  7. 【BZOJ-1787&1832】Meet紧急集合&聚会 倍增LCA

    1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 2259  Solved: 1023[Submit] ...

  8. 「译」JUnit 5 系列:条件测试

    原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...

  9. 「译」JUnit 5 系列:扩展模型(Extension Model)

    原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...

随机推荐

  1. acm数论之旅--中国剩余定理

    ACM数论之旅9---中国剩余定理(CRT)(壮哉我大中华╰(*°▽°*)╯)   中国剩余定理,又名孙子定理o(*≧▽≦)ツ 能求解什么问题呢? 问题: 一堆物品 3个3个分剩2个 5个5个分剩3个 ...

  2. python中的while

    while循环 循环就是一个重复的过程,不断的重复.while循环又称条件循环 while 条件: code 1 code 2 code 3 ... ##实现ATM的输入密码重新输入的功能 while ...

  3. Kettle-User Defined Java Class使用-大写转换

    一.大写转换 (1)步骤(表输入-Java脚本-表输出) (2)配置 1)表输入 2)java脚本 public boolean processRow(StepMetaInterface smi, S ...

  4. python中for循环中的循环变量

    废话不多说,代码伺候: for i in range(3): print("hello") print(i) 运行结果如下: 从上面的例子可以看出,for循环里面的循环变量i作用域 ...

  5. windows jdk8

    C:\Program Files (x86)\Java\jdk1.8.0_65 //JAVA_HOME .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.j ...

  6. Halcon blob分析基本处理步骤

    Halcon,blob分析 应用场景,二值化后的灰度图像对比度清晰 基本处理流程 1 读取图片 read_image(变量名,'路径') //halcon字符串使用单引号'' 2 预处理 2.1 RO ...

  7. 安卓开发:Password verification failed

    2019年8月5日更新: 我把Android Studio升级到3.4.2版本后,发现下图中的按钮已经不见了,所以本文中之前的创建签名文件的方法已经不行了- ...3.4.2版本是这样的---> ...

  8. 忘记linux下的mysql密码,需要重新创建密码123456

    你必须要有操作系统的root权限了. # mysqld_safe --skip-grant-tables & &,表示在后台运行,不再后台运行的话,就再打开一个终端咯. # mysql ...

  9. Beego Learning Notes

    Beego框架学习 1.1软件框架 一个公司是由公司中的各部部门来组成的,每一个部门拥有特定的职能,部门与部门之间通过相互的配合来完成让公司运转起来. 一个软件框架是由其中各个软件模块组成的,每一个模 ...

  10. vs2019本地调试异步程序

    1.vs2019创建一个webapi服务,启动本地webapi服务, 2.使用vs2019再打开一个相同的应用程序,并将异步程序所在的程序集设置为启动项,并启动,启动后点击调试->全部拆离 3. ...