LUOGU 3379 RMQ求LCA

LUOGU 3379
Description
求树上两点x,y的LCA。

Input Format
第一行包含三个正整数N,M,S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来N-1行每行包含两个正整数x,y,表示x结点和y结点之间有一条直接连接的边。
接下来M行每行包含两个正整数a,b,表示询问a结点和b结点的最近公共祖先。

Output Format
输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

Sample Input

5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5

Sample Output

4
4
1
4
4

Constraints
对于100%的数据,M \leq 5 \times 10^5,N \leq 5 \times 10^5

CCYOS
LCA板子题,RMQ做法可以做到常数回答询问。
前置技能

  • RMQ(ST表)
  1. 概念
    时间戳 - 该结点dfs首次遍历到的序号,用dfn记录。
    欧拉序 - dfs遍历节点,节点的编号形成的序列,用ol记录。(包括回溯)
  2. 在欧拉序上进行RMQ:
    depth[i][j]表示从i开始包括自身在内的2^j个节点中的深度最小值,
    id[i][j]表示与depth[i][j]对应的节点编号,也就是这2^j个节点的LCA。
    LCA在ol[dfn[x]],ol[dfn[y]]之间(闭区间)且是其中深度最小的节点,这是显然的:(设dfn[x] < dfn[y]
    (x,y)有两种情况,xy的祖先,此时向下遍历一定会到达y
    x不是y的祖先,由于树上路径x,y的唯一性,在到达x后必然会退出x,经过LCA(x,y),到达y

注意
a)处理RMQ数组时,欧拉序上的位置i须循环到 cnt - (1 << j) + 1
j + (1 << i) - 1 <= cnt,这2^j个节点包括i自己;cnt表示获得的欧拉序的长度
b)ST表的输出,不能写成

while(l + (1 << k) <= r)++k;
printf("%d\n",id[l][k]);

会更新2 ^ k( \geq {|r - l|})个子节点的LCA导致答案偏小。
code

#include<bits/stdc++.h>
using namespace std;

#define mxn 500005
int N,M,R,tot,cnt;
int dfn[mxn],ol[mxn << 1],dep[mxn],head[mxn];
int depth[mxn << 1][22],id[mxn << 1][22];
struct edge{
    int to,nxt;
}edg[mxn << 1];

inline int read(){
    char c = getchar();
    int ret = 0,fl = 1;
    for(;!isdigit(c)&&c != '-';c = getchar())if(c == '-')fl = 0;
    for(;isdigit(c);c = getchar())ret = (ret << 3) + (ret << 1) + c - 48;
    return fl ? ret : -ret;
}

inline void add(int x,int y){
    edg[++tot].to = y;
    edg[tot].nxt = head[x];
    head[x] = tot;
}

inline void dfs(int u,int f){
    ol[++cnt] = u,dfn[u] = cnt,dep[u] = dep[f] + 1;
    for(int e = head[u];e;e = edg[e].nxt){
        int to = edg[e].to;
        if(to == f)
            continue;
        dfs(to,u);
        ol[++cnt] = u;
    }
}

int main(){
    N = read();M = read();R = read();
    for(int i = 1;i < N;++i){
        int x,y;
        x = read();y = read();
        add(x,y);add(y,x);
    }
    dfs(R,0);
    for(int i = 1;i <= cnt;++i)depth[i][0] = dep[ol[i]],id[i][0] = ol[i];
    for(int j = 1;j <= 22;++j)
        for(int i = 1;i <= cnt - (1 << j) + 1;++i){
            if(depth[i][j - 1] > depth[i + (1 << (j - 1))][j - 1])
                depth[i][j] = depth[i + (1 << (j - 1))][j - 1],
                id[i][j] = id[i + (1 << (j - 1))][j - 1];
            else 
                depth[i][j] = depth[i][j - 1],
                id[i][j] = id[i][j - 1];
        //  cout<<"          "<<i<<" "<<j<<" "<<id[i][j]<<endl;
        }
    for(int i = 1;i <= M;++i){
        int l,r;l = read();r = read();
        l = dfn[l],r = dfn[r];
        if(r < l)swap(l,r);
        int k = 0;
        while(l + (1 << k) <= r)++k;
        k--;
        if(depth[l][k] < depth[r - (1 << k) + 1][k])printf("%d\n",id[l][k]);//!!!
        else printf("%d\n",id[r - (1 << k) + 1][k]);
    }
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 相看两不厌,只有敬亭山
    是长安阅读 320评论 0 1
  • 001读绘本的方法 先和孩子一起看完全部的图片,针对图片提些问题,再读文字,读完后再提问,甚至和孩子一起讨论一下内...
    苏_8ab1阅读 165评论 0 0
  • 没有人知道 风捎过多少心事 是他们不肯亲说 才劳烦了风 可风一出门 就忘了去向 便把捎着的心事 随意投进路过的信箱...
    烺叶之声阅读 162评论 0 0
  • 这里下雨了。。。 夜有点凉了,是谁又忘记了谁了,而又是谁在敲打着谁的记忆。 漆黑是谁走过的痕,无奈又是谁摇曳的湿。...
    心逝无痕风吹雨落阅读 209评论 0 0