题目传送门

Description

给定一棵树上的三个点 \(a,b,c\),你要制定两条起点和终点都在这三个点中的路径,使得两条路径重叠的节点最多。

Solution

感觉我的方法和大众不同,显然是珂以Hack的

考虑分类讨论,分三类:

  1. \(a\) 点在这两条路径的起止点中出现 \(2\) 次。
  2. \(b\) 点在这两条路径的起止点中出现 \(2\) 次。
  3. \(c\) 点在这两条路径的起止点中出现 \(2\) 次。

下面只分析一类,即 \(a\) 出现两次(其实都一样的)。



如图,这时 \(\operatorname{LCA}(b,c)\) 不在 \(a\) 到 \(b\) 的简单路径上或\(\operatorname{LCA}(b,c)\) 不在 \(a\) 到 \(c\) 的简单路径上。

这就是说, \(\operatorname{LCA}(b,c)\) 不会被重复走过。

那么答案就是 \(\operatorname{dis}(a,\operatorname{LCA}(a,c))\) 和 \(\operatorname{dis}(a,\operatorname{LCA}(a,b))\) 中的最小值。(这个理解起来不难)



如图,这时 \(\operatorname{LCA}(b,c)\) \(a\) 到 \(b\) 的简单路径上且\(\operatorname{LCA}(b,c)\) \(a\) 到 \(c\) 的简单路径上。

这就是说, \(\operatorname{LCA}(b,c)\) 会被重复走过。

那么答案就是 \(\operatorname{dis}(a,\operatorname{LCA}(b,c))\) 。(这个理解起来更不难)

然后这题就愉快地做完了。

Code

#include<stdio.h>
#define reg register
#define ri reg int
#define rep(i, x, y) for(ri i = x; i <= y; ++i)
#define nrep(i, x, y) for(ri i = x; i >= y; --i)
#define DEBUG 1
#define INF 0x3fffffff
#define ll long long
#define il inline
#define swap(a, b) ((a) ^= (b) ^= (a) ^= (b))
#define max(i, j) (i) > (j) ? (i) : (j)
#define min(i, j) (i) < (j) ? (i) : (j)
#define read(i) io.READ(i)
#define print(i) io.WRITE(i)
#define push(i) io.PUSH(i)
struct IO {
#define MAXSIZE (1 << 20)
#define isdigit(x) (x >= '0' && x <= '9')
char buf[MAXSIZE], *p1, *p2;
char pbuf[MAXSIZE], *pp;
#if DEBUG
#else
IO() : p1(buf), p2(buf), pp(pbuf) {}
~IO() {
fwrite(pbuf, 1, pp - pbuf, stdout);
}
#endif
inline char gc() {
#if DEBUG
return getchar();
#endif
if(p1 == p2)
p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin);
return p1 == p2 ? ' ' : *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
template <class T>
inline void READ(T &x) {
register double tmp = 1;
register bool sign = 0;
x = 0;
register char ch = gc();
for(; !isdigit(ch); ch = gc())
if(ch == '-') sign = 1;
for(; isdigit(ch); ch = gc())
x = x * 10 + (ch - '0');
if(ch == '.')
for(ch = gc(); isdigit(ch); ch = gc())
tmp /= 10.0, x += tmp * (ch - '0');
if(sign) x = -x;
}
inline void READ(char *s) {
register char ch = gc();
for(; blank(ch); ch = gc());
for(; !blank(ch); ch = gc())
*s++ = ch;
*s = 0;
}
inline void READ(char &c) {
for(c = gc(); blank(c); c = gc());
}
inline void PUSH(const char &c) {
#if DEBUG
putchar(c);
#else
if(pp - pbuf == MAXSIZE) {
fwrite(pbuf, 1, MAXSIZE, stdout);
pp = pbuf;
}
*pp++ = c;
#endif
}
template <class T>
inline void WRITE(T x) {
if(x < 0) {
x = -x;
PUSH('-');
}
static T sta[35];
T top = 0;
do {
sta[top++] = x % 10;
x /= 10;
} while(x);
while(top)
PUSH(sta[--top] + '0');
}
template <class T>
inline void WRITE(T x, char lastChar) {
WRITE(x);
PUSH(lastChar);
}
} io;
struct Edge {
int to, nxt, val;
} e[1000010];
int n, q, cnt, head[1000010], fath[1000010][22], dep[1000010], s, lg[500010];
void add(int u, int v, int val) {
e[++cnt].to = v;
e[cnt].nxt = head[u];
e[cnt].val = val;
head[u] = cnt;
}
void dfs(int now, int fa) {
dep[now] = dep[fa] + 1;
fath[now][0] = fa;
rep(i, 1, lg[dep[now]]) fath[now][i] = fath[fath[now][i - 1]][i - 1];
for(int i = head[now]; i; i = e[i].nxt) if(e[i].to != fa) dfs(e[i].to, now);
}
int lca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
while(dep[x] > dep[y]) x = fath[x][lg[dep[x] - dep[y]] - 1];
if(x == y) return x;
nrep(i, lg[dep[x]] - 1, 0) if(fath[x][i] != fath[y][i]) x = fath[x][i], y = fath[y][i];
return fath[x][0];
}
int abs(int x) { return x < 0 ? -x : x; }
int dis(int x, int y) {
int l = lca(x, y);
return abs(dep[l] - dep[x]) + abs(dep[l] - dep[y]);
}
int check(int a, int b, int c) {
if(dis(a, c) + dis(b, c) == dis(a, b)) return 1;
return 0;
}
int solve(int a, int b, int c) {
if(check(a, b, lca(b, c)) && check(a, c, lca(b, c))) return dis(a, lca(b, c));
return min(dis(a, lca(a, b)), dis(a, lca(a, c)));
}
int main() {
read(n), read(q);
rep(i, 2, n) {
int x;
read(x);
add(x, i, 1), add(i, x, 1);
}
rep(i, 1, n) lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
dfs(1, 0);
rep(i, 1, q) {
int x, y, z;
read(x), read(y), read(z);
int ans = max(solve(x, y, z), max(solve(y, x, z), solve(z, x, y)));
printf("%d\n", ans);
}
return 0;
}

CF832D题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

随机推荐

  1. SuperEdge 云边隧道新特性:从云端SSH运维边缘节点

    背景 在边缘集群的场景下边缘节点分布在不同的区域,且边缘节点和云端之间是单向网络,边缘节点可以访问云端节点,云端节点无法直接访问边缘节点,给边缘节点的运维带来很大不便,如果可以从云端SSH登录到边缘节 ...

  2. [Linux]Ansible自动化运维① - 入门知识

    目录 一.Ansible 概述 1.1 Ansible 是什么 1.2 Ansible 优势 1.3 Ansible 特性 二.Ansible 入门 2.1 Ansible 架构 2.2 Ansibl ...

  3. centos 8 gitlab 重置管理员的密码

    登录gitlab安装服务器 由于 root 账户用的很少,所以我们容易忘记它的密码,但不代表它不重要,类似 linux 的 root 账户:一旦我们忘记了 root 账号的密码,我们需要知道重置的方法 ...

  4. 18 shell 重定向以及文件描述符

    1.对重定向的理解 2.硬件设备和文件描述符 文件描述符到底是什么 3.Linux Shell 输出重定向 4.Linux Shell 输入重定向 5.结合Linux文件描述符谈重定向 6.Shell ...

  5. linux安装subversion

    原文: https://www.cnblogs.com/liuxianan/p/linux_install_svn_server.html 安装 使用yum安装非常简单: yum install su ...

  6. XCTF_MFC逆向

    讲道理这题有点脑洞,也可能我太菜了,首先对mfc就不太熟悉,不知道是个啥玩意,只能边看大佬的wp百度边做了,之后要恶补一下mfc的知识了. 题目一开始说flag在控件中,看到大佬都是用Mfcspy来找 ...

  7. Java 设置PDF跨页表格重复显示表头行

    在创建表格时,如果表格内容出现跨页显示的时候,默认情况下该表格的表头不会在下一页显示,在阅读体验上不是很好.下面分享一个方法如何在表格跨页是显示表格的表头内容,这里只需要简单使用方法 grid.set ...

  8. nmon工具安装及nmon analyser的使用

    步骤一:下载nmon及nmon analyser工具 nmon:http://nmon.sourceforge.net/pmwiki.php 根据自己系统的版本下载相应的版本即可 nmon analy ...

  9. ROS2学习之旅(21)——创建一个动作服务和客户节点(C++)

    动作是ROS中的一种异步通信形式,动作客户端向动作服务器发送目标请求,目标服务器向操作客户端发送目标反馈和结果.本文基于前一篇自定义动作博文. 1.创建一个action_turtorials_cpp包 ...

  10. NIO 输入输出

    NIO 是java14 API 提供的一种新输入输出流,一套用于标准IO的文件读写,一套用于网络编程. 1. NIO 与IO 的区别 IO流以字节流输入输出,一次以一个字节进行数据操作,效率慢: NI ...