最近公共祖先(LCT)

来一发LCTLCA

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

但是却是一道LCT的练手题

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

而且不难发现,有一个很妙的性质:如果两个点不在一条路径上(即lca!=a||lca!=b)那么b点access以后,b第一次到a到rootSplay的上的点即为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;
}
posted @   呢没理他  阅读(302)  评论(0编辑  收藏  举报
编辑推荐:
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
阅读排行:
· [翻译] 为什么 Tracebit 用 C# 开发
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
点击右上角即可分享
微信分享提示