【树链剖分】洛谷P3379 树链剖分求LCA
题目描述
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入输出格式
输入格式:
第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。
接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。
输出格式:
输出包含M行,每行包含一个正整数,依次为每一个询问的结果。
输入输出样例
5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5
4
4
1
4
4
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=10,M<=10
对于70%的数据:N<=10000,M<=10000
对于100%的数据:N<=500000,M<=500000
样例说明:
该树结构如下:

第一次询问:2、4的最近公共祖先,故为4。
第二次询问:3、2的最近公共祖先,故为4。
第三次询问:3、5的最近公共祖先,故为1。
第四次询问:1、2的最近公共祖先,故为4。
第五次询问:4、5的最近公共祖先,故为4。
故输出依次为4、4、1、4、4。
题解
emmmmmm
这道题听说倍增写得丑了就过不了。。。
所以我正好拿最近刚学的树链剖分练练手
虽然看到题解里有树剖。。。
但我自认为自己写的比较优美。。。
而且最关键的是题解里好多都在说树剖慢。。。
他们怕不是写了假的树剖。。。
下面给出严格【并不】的复杂度证明:
树剖要用到两次dfs,都是O(n)的复杂度
然后如果图是满二叉树的话是最坏情况,但此时查询也是O(logn)的
【显然最坏情况每次一步步取f[top[x]]走,走下来是一个树的深度,也就是一个logn】
所以理论复杂度上界就是O(2n+mlogn)
而且关键的是树剖常数还比倍增要小。。。
倍增的话常数虽然也很小
但是某集训队dalao写过一篇论文里面有严格的树剖的常数证明,计算结果是树剖的常数接近1/2
再加上树剖用的的空间也比倍增啊RMQ啊小
所以写树剖是完全没问题滴~
那么下面就简单说下树剖思路咯
树剖就是把树剖分成若干条不相交的链,目前常用做法是剖成轻重链
所以我们定义siz[x]为以x为根结点的子树的结点个数
对于每个结点x,在它的所有子结点中寻找一个结点y
使得对于y的兄弟节点z,都有siz[y]≥siz[z]
此时x就有一条重边连向y,有若干条轻边连向他的其他子结点【比如z】
这样的话,树上的不在重链上的边的数量就会大大减少
然后我们每次求LCA(x,y)的时候就可以判断两点是否在同一链上
如果两点在同一条链上我们只要找到这两点中深度较小的点输出就行了
如果两点不在同一条链上
那就找到深度较大的点令它等于它所在的重链链端的父节点即为x=f[top[x]]
直到两点到达同一条链上,输出两点中深度较小的点
代码如下
//by 减维
#include<cstdio>
#include<iostream>
using namespace std;
struct edge{
int to,ne;
}e[];
int n,m,s,ecnt,head[],dep[],siz[],son[],top[],f[];
void add(int x,int y)
{
e[++ecnt].to=y;
e[ecnt].ne=head[x];
head[x]=ecnt;
}
void dfs1(int x)
{
siz[x]=;
dep[x]=dep[f[x]]+;
for(int i=head[x];i;i=e[i].ne)
{
int dd=e[i].to;
if(dd==f[x])continue;
f[dd]=x;
dfs1(dd);
siz[x]+=siz[dd];
if(!son[x]||siz[son[x]]<siz[dd])
son[x]=dd;
}
}
void dfs2(int x,int tv)
{
top[x]=tv;
if(son[x])dfs2(son[x],tv);
for(int i=head[x];i;i=e[i].ne)
{
int dd=e[i].to;
if(dd==f[x]||dd==son[x])continue;
dfs2(dd,dd);
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=;i<n;++i)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs1(s);
dfs2(s,s);
for(int i=;i<=m;++i)
{
int x,y;
scanf("%d%d",&x,&y);
while(top[x]!=top[y])
{
if(dep[top[x]]>=dep[top[y]])x=f[top[x]];
else y=f[top[y]];
}
printf("%d\n",dep[x]<dep[y]?x:y);
}
}
【树链剖分】洛谷P3379 树链剖分求LCA的更多相关文章
- 洛谷 3379 最近公共祖先(LCA 倍增)
洛谷 3379 最近公共祖先(LCA 倍增) 题意分析 裸的板子题,但是注意这题n上限50w,我用的边表,所以要开到100w才能过,一开始re了两发,发现这个问题了. 代码总览 #include &l ...
- 洛谷P3379 【模板】最近公共祖先(LCA)(树链剖分)
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器
刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...
- 洛谷P3384 树链剖分
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x ...
- 洛谷P2146 树链剖分
题意 思路:直接树链剖分,用线段树维护即可,算是树剖的经典题目吧. 代码: #include <bits/stdc++.h> #define ls(x) (x << 1) #d ...
- 洛谷 P3379 【模板】最近公共祖先(LCA)
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 【倍增】洛谷P3379 倍增求LCA
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 【RMQ】洛谷P3379 RMQ求LCA
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 【Tarjan】洛谷P3379 Tarjan求LCA
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
随机推荐
- HLJU 1223: 寻找区间和 (交替推进法)
1223: 寻找区间和 Time Limit: 3 Sec Memory Limit: 128 MB Submit: 13 Solved: 4 [Submit][Status][pid=1223& ...
- 你为什么还坚持.NET
C#换什么比较合适? 从TIOBE来看,Java.C++.C.Python都好,对了,还不能忘了JS. Sql Server换什么比较合适? MySql挺好,Oracle也不错,也还有不少选择. 都挺 ...
- Winform开发框架中工作流模块之申请单草稿处理
在我们开发工作流模块的时候,有时候填写申请单过程中,暂时不想提交审批,那么可以暂存为草稿,以供下次继续填写或者提交处理,那么这个草稿的功能是比较实用的,否则对于一些填写内容比较多的申请单,每次要重填写 ...
- 自学Zabbix3.5.3-监控项item-key
1. 温习 Zabbix server是Zabbix软件的中心进程. Server执行polling和trapping来采集数据,评估是否触发触发器,发送报警给用户.它是Zabbix agent和pr ...
- MySQL 导入外部数据时报错:1153: Got a packet bigger than 'max_allowed_packet' 解决方案
MySQL 导入外部数据时报错:1153: Got a packet bigger than 'max_allowed_packet' 解决方案 zoerywzhou@163.com http://w ...
- 微信小程序各类型的自定义组件篇
由于本人最近在开发小程序项目,期间对小程序有花点时间去研究,同时也找了网上大牛的一些案例,在这里分享部分自定义组件,部分代码是copy大牛案例的,有对小程序有兴趣的伙伴拿走,不谢! 源码下载地址:ht ...
- javascript中的双向绑定
阅读目录 一:发布订阅模式实现数据双向绑定 二:使用Object.defineProperty 来实现简单的双向绑定. 前言: 双向数据绑定的含义:可以将对象的属性绑定到UI,具体的说,我们有一个对象 ...
- Android开发——导入github安卓项目源码
之前在Github上看见其他人的安卓项目源码,便是想下载源码来学习学习,但是下载之后一直导入失败,经过了漫长的摸索终于是成功了,便是分享一下经验 首先进入Github官网,找到想要学习的安卓源码 右上 ...
- JSON--stringify() 和 parse() 方法
序列化:stringify()将JavaScript对象序列号为JSON字符串反序列化:parse()将JSON字符串解析为原生JavaScript值 序列化选项:JSON.stringify()除了 ...
- 数值函数ROUND(四舍五入),TRUNC(不四舍五入),MOD