来一发\(LCT\)求\(LCA\)

\(LCT\)在时间上不占据优势,码量似乎还比树剖,倍增,\(Tarjan\)大一点

但是却是一道\(LCT\)的练手题

对于每一个询问,我们只需要把其中一个点(我们设为a)先\(access\),这样a到根节点的路径就都在一棵\(Splay\)里面了

而且不难发现,有一个很妙的性质:如果两个点不在一条路径上(即\(lca!=a||lca!=b\))那么b点\(access\)以后,b第一次到a到\(root\)的\(Splay\)的上的点即为\(LCA\)

然后我们考虑在将另一个点(我们设为b)与根的路径打通,我们还是一样一直\(Splay\),对于最后一棵\(Splay\)

\(LCA\)即为b第一次到a和rt的那一棵\(Splay\)的位置

那么a,b本来在一个\(Splay\)上呢?

其实也是一样的,我们在分类讨论

1)若\(dep[a]>dep[b]\)那么显然不影响答案,答案就是b点

2)若\(dep[a]<dep[b]\)那么我们在\(access(a)\)时候,a,b就已经不在一颗\(Splay\)里了,所以也不影响答案

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
il int read()
{
re int x = 0, f = 1; re char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
return x * f;
}
#define get_fa(x) (ch[1][fa[x]] == x)
#define isroot(x) (ch[1][fa[x]] == x || ch[0][fa[x]] == x)
#define updown(x) swap(ch[1][x], ch[0][x]), tag[x] ^= 1
#define rep(i, s, t) for(re int i = s; i <= t; ++ i)
#define maxn 500005
int n, m, s, ch[2][maxn], fa[maxn], st[maxn], top, tag[maxn];
il void pushdown(int x)
{
if(tag[x])
{
if(ch[0][x]) updown(ch[0][x]);
if(ch[1][x]) updown(ch[1][x]);
tag[x] = 0;
}
}
il void rotate(int x)
{
int y = fa[x], z = fa[y], w = get_fa(x), k = get_fa(y);
if(isroot(y)) ch[k][z] = x;
if(ch[w ^ 1][x]) fa[ch[w ^ 1][x]] = y;
fa[x] = z, fa[y] = x;
ch[w][y] = ch[w ^ 1][x], ch[w ^ 1][x] = y;
}
il void Splay(int x)
{
int y = x;
st[++ top] = x;
while(isroot(y)) st[++ top] = y = fa[y];
while(top) pushdown(st[top --]);
while(isroot(x))
{
int y = fa[x];
if(isroot(y)) rotate(get_fa(x) == get_fa(y) ? y : x);
rotate(x);
}
}
il void access(int x)
{
for(re int y = 0; x; x = fa[y = x]) Splay(x), ch[1][x] = y;
}
il void makeroot(int x) {access(x), Splay(x), updown(x);}
il void link(int a, int b) {makeroot(a), fa[a] = b;}
il int query(int a, int b)
{
access(a);
int ans = 0;
for(; b; b = fa[ans = b]) Splay(b), ch[1][b] = ans;
return ans;
}
int main()
{
n = read(), m = read(), s = read();
rep(i, 1, n - 1){int u = read(), v = read(); link(u, v);}
makeroot(s);
while(m --)
{
int a = read(), b = read();
printf("%d\n", query(a, b));
}
return 0;
}

最近公共祖先(LCT)的更多相关文章

  1. P3379 【模板】最近公共祖先(LCA)(LCT)

    \(\color{#0066ff}{ 题目描述 }\) 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. \(\color{#0066ff}{输入格式}\) 第一行包含三个正整数N.M. ...

  2. LCA最近公共祖先 ST+RMQ在线算法

    对于一类题目,是一棵树或者森林,有多次查询,求2点间的距离,可以用LCA来解决.     这一类的问题有2中解决方法.第一种就是tarjan的离线算法,还有一中是基于ST算法的在线算法.复杂度都是O( ...

  3. 【转】最近公共祖先(LCA)

    基本概念 LCA:树上的最近公共祖先,对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. RMQ:区间最小值查询问题.对于长度为n的 ...

  4. 【并查集】【树】最近公共祖先LCA-Tarjan算法

    最近公共祖先LCA 双链BT 如果每个结点都有一个指针指向它的父结点,于是我们可以从任何一个结点出发,得到一个到达树根结点的单向链表.因此这个问题转换为两个单向链表的第一个公共结点(先分别遍历两个链表 ...

  5. 洛谷P3379 【模板】最近公共祖先(LCA)

    P3379 [模板]最近公共祖先(LCA) 152通过 532提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 为什么还是超时.... 倍增怎么70!!题解好像有 ...

  6. Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)【转】【修改】

    一.基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成 ...

  7. 数据结构作业——sights(最短路/最近公共祖先)

    sights Description 美丽的小风姑娘打算去旅游散心,她走进了一座山,发现这座山有 n 个景点,由于山路难修,所以施工队只修了最少条的路,来保证 n 个景点联通,娇弱的小风姑娘不想走那么 ...

  8. [最近公共祖先] POJ 3728 The merchant

    The merchant Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 4556   Accepted: 1576 Desc ...

  9. [最近公共祖先] POJ 1330 Nearest Common Ancestors

    Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 27316   Accept ...

  10. 图论--最近公共祖先问题(LCA)模板

    最近公共祖先问题(LCA)是求一颗树上的某两点距离他们最近的公共祖先节点,由于树的特性,树上两点之间路径是唯一的,所以对于很多处理关于树的路径问题的时候为了得知树两点的间的路径,LCA是几乎最有效的解 ...

随机推荐

  1. OO_BLOG2_多线程电梯模拟

    作业2-1 单部多线程傻瓜调度(FAFS)电梯的模拟 I. 基于度量的程序结构分析 1)程序结构与基本度量统计图 2)分析 ​ 这次作业基本奠定了本人三次电梯作业的基本架构,简述如下: Elevato ...

  2. Spring MVC(一)五大核心组件和配置

    一,五大核心组件 1.DispatcherServlet 请求入口 2.HandlerMapping   请求派发,负责请求和控制器建立一一对应的关系 3.Controller   处理器 4.Mod ...

  3. WEB前端需要了解的XML相关基础知识

    什么是 XML? XML 指可扩展标记语言(EXtensible Markup Language) XML 是一种标记语言,很类似 HTML XML 的设计宗旨是传输数据,而非显示数据 XML 标签没 ...

  4. 图像的膨胀与腐蚀——OpenCV与C++的具体实现

    目录 1. 膨胀与腐蚀的原理 2. 膨胀的具体实现 1) OpenCV实现 2) C/C++实现 3) 验证与结果 3. 腐蚀的具体实现 1. 膨胀与腐蚀的原理 膨胀与腐蚀是数学形态学在图像处理中最基 ...

  5. 48.Odoo产品分析 (五) – 定制板块(3) – 修改文件和报告(1)

    查看Odoo产品分析系列--目录 不管ERP系统中的内置报表有多完善,大多数的公司仍然需要对文档和报表进行一些自定义的修改.  这一章节将介绍如何对报表的页眉和页脚做自定义修改:odoo框架如何组织报 ...

  6. 一起学Android之ProgressBar

    本文简述在Android开发中进度条(ProgressBar)的常见应用,仅供学习分享使用. 概述 在Android开发中,进度条的使用场景有很多,如播放电影时可拖动的观看进度条,评分时使用的评分条, ...

  7. Android远程桌面助手(B1185)for Android P开发者预览版

    Android P的开发者预览版已出,其中App compatibility changes部分特别强调“The platform restricts the use of some non-SDK ...

  8. RAID5当一块硬盘离线后处理

    RAID5当一块硬盘离线后,处理降级状态,这时候正常的建议是马上更换硬盘做REBUILD以恢复完整的数据状态,如果有热备盘的话,就会自动做REBUILD,这样做合适吗? 一组RAID卷在工作很长时间以 ...

  9. Linux学习历程——SUID、SGID、SBIT简介

    一.SUID.SGID.SBIT简介 SUID:对一个可执行文件,不是以发起者身份来获取资源,而是以可执行文件的属主身份来执行.SGID:对一个可执行文件,不是以发起者身份来获取资源,而是以可执行文件 ...

  10. c++11の关联容器

    一.关联容器 C++的容器类型可以分为顺序容器和关联容器两大类.对于关联容器,主要有map和set,对于这两种,根据不同的维度,衍生出了8种容器 map                        ...