「LCA」仓鼠找sugar
时间:2019-09-06
本文章向大家介绍「LCA」仓鼠找sugar,主要包括「LCA」仓鼠找sugar使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
仓鼠找sugar
原题链接 仓鼠找sugar
题目大意
给你 \(n\) 个点, \(q\) 次询问,\(n - 1\) 条边,每条边给出 \(u, v\) 两个点,代表 \(u, v\) 被一条边连接,接下来是\(q\)次询问,每次询问给你 \(x_1,y_1,x_2,y_2\) 让你判断 \(x_1\) 到 \(y_1\) 与 \(x_2\) 到 \(y_2\) 是否会经过相同的点
题目题解
跑LCA,然后判断
dist<x1, y1> + dist<x2, y2> >= dist<x1, x2> + dist<y1, y2>
dist<x, y> = depth[x] + depth[y] - 2 × depth[lca(x, y)]
第二个就是一个计算两点深度的,不多做解释,重点关注第一个不等式,以下证明正确性
分类证明:
- 对于一棵树而言 \(x_1,y_1\) 在根节点的左树里面, \(x_2, y_2\) 在根节点的右树里面 这样一定满足不等式
- 对于一棵树而言 \(x_1.y_1,x_2,y_2\) 同时在根节点的左树(右树)里,那么此时又分情况
- 将其左树(右树)看成一棵以原根节点的下一个节点为根节点的树,此时分三种情况
- \(x_1,y_1\) 与 \(x_2, y_2\) 在不同边,此时满足我们第一点所说
- \(x_1\) 或某一个点在左树,其他点在右树,将左侧的\(x_1\)或其他点与右树应该加的点进行加法,然后再将右树的点用第一点所说处理即可,最终可以发现是满足我们的不等式
- \(x_1, y_2\) 同树,\(x_2,y_1\) 同树 参考第一点进行处理
- 还有一种没有意义的情况就是再出现同在左树右树的情况 再以原树的根节点的下一点为根进行处理即可
- 若就在原树中发生上述情况,也可按上述情况来进行处理,任何形态都是一样的
详细看代码
//#define fre yes
#include <cstdio>
#include <cstring>
#include <iostream>
const int N = 100005;
int head[N << 1], to[N << 1], ver[N << 1];
int depth[N], f[N][22], lg[N];
bool Vis[N];
int tot;
void addedge(int x, int y) {
ver[tot] = y;
to[tot] = head[x];
head[x] = tot++;
}
void dfs(int x, int fa) {
depth[x] = depth[fa] + 1;
f[x][0] = fa;
for (int i = 1; (1 << i) <= depth[x]; i++) {
f[x][i] = f[f[x][i - 1]][i - 1];
}
for (int i = head[x]; ~i; i = to[i]) {
int v = ver[i];
if(v != fa) {
Vis[v] = 1;
dfs(v, x);
}
}
}
int lca(int a, int b) {
if(depth[a] < depth[b]) {
std::swap(a, b);
}
while(depth[a] > depth[b]) {
a = f[a][lg[depth[a] - depth[b]] - 1];
}
if(a == b) return a;
for (int i = lg[depth[a]] - 1; i >= 0; i--) {
if(f[a][i] != f[b][i]) {
a = f[a][i];
b = f[b][i];
}
} return f[a][0];
}
int dist(int a, int b) {
return depth[a] + depth[b] - 2 * depth[lca(a, b)];
}
int main() {
memset(head, -1, sizeof(head));
static int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d %d", &u, &v);
addedge(u, v);
addedge(v, u);
}
for (int i = 1; i <= n; i++) {
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
}
for (int i = 1; i <= n; i++) {
if(!Vis[i]) {
Vis[i] = 1;
dfs(i, -1);
}
}
for (int i = 1; i <= m; i++) {
int x1, x2, y1, y2;
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
if(dist(x1, y1) + dist(x2, y2) >= dist(x1, x2) + dist(y1, y2)) puts("Y");
else puts("N");
} return 0;
}
原文地址:https://www.cnblogs.com/Nicoppa/p/11477981.html
- 了解你服务器的心情——top命令详解
- HTML5视音频代码实例 & WEBM格式转换器
- 解析Tensorflow官方PTB模型的demo
- MyBatis源码解析(一)——MyBatis初始化过程解析
- MyBatis源码解析(二)——动态代理实现函数调用
- Git命令速记
- linux设备驱动第三篇:如何写一个简单的字符设备驱动
- Tensorflow高级API的进阶--利用tf.contrib.learn建立输入函数
- Spring速查手册(三)——Spring+JDBC
- [WebKit] JavaScriptCore解析--基础篇(一)字节码的生成及抽象语法树的构建详情分析
- Spring速查手册(二)——Bean的作用域
- pyTorch自然语言处理简单例子
- 一文初探Tensorflow高级API使用(初学者篇)
- Spring速查手册——Bean装配
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python爬虫:无账号无限制获取企查查信息
- Spark Streaming——Spark第一代实时计算引擎
- bamtools分割bam文件
- 在genome browser中添加自己的注释文件
- 原理+代码|Python基于主成分分析的客户信贷评级实战
- Python办公自动化 | 从PPT到Word
- linux命令行参数getopts参数二选一
- 黎巴嫩首都爆炸能量有多大?物理学家看视频计算:300吨TNT!
- OracleDG 环境主备业务数据不同步备库报ORA-600错误的处理过程
- Xcode清理模拟器文件
- 【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】六、FFmpeg简单合成MP4:视屏解封与重新封装
- 32.opengl高级光照-延迟着色法
- Tsunami:一款功能强大的通用网络安全扫描工具
- Hive查看表/分区更新时间
- 直接通过手机抓取GPS的qxdm日志