【模板】倍增LCA [2017年5月计划 清北学堂51精英班 Day3]

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

题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入输出格式

输入格式:

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出格式:

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

输入输出样例

输入样例#1:

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

输出样例#1:

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。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 #define max(a,b) ((a) > (b) ? (a) : (b))
 7 #define min(a,b) ((a) > (b) ? (b) : (a))
 8 #define lowbit(a) (a & (-(a)))
 9 const int INF = 0x3f3f3f3f;
10 const int MAXN = 500000 + 10;
11 const int MAXM = 500000 + 10;
12 const int MAXX = 23;
13 inline void read(int &x)
14 {
15     x = 0;char ch = getchar();char c = ch;
16     while(ch > ‘9‘ || ch < ‘0‘)c = ch, ch = getchar();
17     while(ch >= ‘0‘ && ch <= ‘9‘)x = x * 10 + ch - ‘0‘,ch = getchar();
18     if(c == ‘-‘)x = -x;
19 }
20 inline void swap(int &a,int &b)
21 {
22     int tmp = a;
23     a = b;
24     b = tmp;
25 }
26 int n, m, root, head[MAXN], cnt, tmp1, tmp2, deep[MAXN], lca[MAXN][MAXX];
27 bool b[MAXN];
28
29 struct Edge{int u,v,next;}edge[MAXN];
30 void insert(int a,int b){edge[++cnt] = Edge{a, b, head[a]};head[a] = cnt;}
31
32 void dfs(int v, int step)
33 {
34     b[v] = true;
35     deep[v] = step;
36     for(int pos = head[v];pos;pos = edge[pos].next)
37     {
38         int x = edge[pos].v;
39         if(!b[x])
40         {
41             lca[x][0] = v;
42             dfs(x, step + 1);
43         }
44     }
45 }
46 void yu()
47 {
48     for(int j = 1;(1 << j) <= n;j ++)
49     {
50         for(int i = 1;i <= n;i ++)
51         {
52             if(lca[i][j - 1] != -1)
53             {
54                 lca[i][j] = lca[lca[i][j - 1]][j - 1];
55             }
56         }
57     }
58 }
59 int LCA(int va,int vb)
60 {
61     if(deep[va] < deep[vb])swap(va, vb);
62     int i = 0,j = 0;
63     for(;(1 << i) <= deep[va];i ++);
64     i --;
65     for(int j = i;j >= 0;j --)
66     {
67         if(deep[va] - (1 << j) >= deep[vb])
68             va = lca[va][j];
69     }
70     if(va == vb)return va;
71     for(j = i;j >= 0;j --)
72     {
73         if(lca[va][j] != -1 && lca[va][j] != lca[vb][j])
74         {
75             va = lca[va][j];
76             vb = lca[vb][j];
77         }
78     }
79     return lca[va][0];
80 }
81 int main()
82 {
83     read(n);read(m);read(root);
84     for(int i = 1;i < n;i ++)
85     {
86         read(tmp1);read(tmp2);
87         insert(tmp1, tmp2);
88         insert(tmp2, tmp1);
89     }
90     dfs(root, 0);
91     yu();
92     for(int i = 1;i <= m;i ++)
93     {
94         read(tmp1);read(tmp2);
95         printf("%d\n", LCA(tmp1, tmp2));
96     }
97     return 0;
98 }
时间: 2024-12-15 07:00:29

【模板】倍增LCA [2017年5月计划 清北学堂51精英班 Day3]的相关文章

洛谷P1080 [NOIP2012提高组D1T2]国王游戏 [2017年5月计划 清北学堂51精英班Day1]

P1080 国王游戏 题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍的最前面.排好队后,所有的大臣都会获得国王奖赏的若干金币,每 位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右 手上的数,然后向下取整得到的结果. 国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序, 使得获得奖赏最多的大

P2327 [SCOI2005]扫雷 [2017年5月计划 清北学堂51精英班Day1]

P2327 [SCOI2005]扫雷 题目描述 输入输出格式 输入格式: 第一行为N,第二行有N个数,依次为第二列的格子中的数.(1<= N <= 10000) 输出格式: 一个数,即第一列中雷的摆放方案数. 输入输出样例 输入样例#1: 2 1 1 输出样例#1: 2 其实还是扫雷玩的少..知道思路之后很快 只需枚举前两个各自的情况,后面的各自便能够计算出来 注意几个细节(在代码里面) #include <iostream> #include <cstdio> #in

【模板】 递归线段树 [2017年五月计划 清北学堂51精英班Day4]

P3372 [模板]线段树 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的

【模板】tyvjP1520 树的直径 [2017年5月计划 清北学堂Day3]

P1520 树的直径 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 树的直径,即这棵树中距离最远的两个结点的距离.每两个相邻的结点的距离为1,即父亲结点与儿子结点或儿子结点与父子结点之间的距离为1.有趣的是,从树 的任意一个结点a出发,走到距离最远的结点b,再从结点b出发,能够走的最远距离,就是树的直径.树中相邻两个结点的距离为1.你的任务是:给定一棵树, 求这棵树中距离最远的两个结点的距离. 输入格式 输入共n行第一行是一个正整数n,表示这棵树的结点

2017年7月计划

6月的最后一天,我完成了六月计划,打卡 7月07日~14日将在郑州河南省实验度过 7月15日~22日将在济南清北学堂度过 7月25日~8月2日将在日照一中度过 8月05日~11日将在青岛二中度过 于是...定下如下计划: 1.动态规划百题斩开启  难度在提高及以上.100道题, 包括: 状压DP                                    15道 区间DP                                    10道 树上DP 10道 数位DP 10道

【计划】2017年5月计划

由于上次计划制定时已经是月中了,弄得有点多,削减了一点. 从清北回来,最后一次借着众dalao意外失利,我接近AK了(有一个数据点有点小问题,拿了290分),小激动,愈发砥砺前行. 1.完成四月计划(5.11日) 2.清北学堂Day1题目(18日) 3.清北学堂Day2题目(25日) 4.清北学堂Day3题目(30日) 嗯..总之先这样 还剩Day4和Day5,争取下次去清北前搞完吧 Day6一天可完,上午数论,下午AK(逃)  DayNOIP原题,打算以后抽个时间集中做一下 就这样.

【模板】LIS模板 洛谷P1091 [NOIP2004提高组]合唱队形 [2017年4月计划 动态规划11]

以题写模板. 写了两个:n^2版本与nlogn版本 P1091 合唱队形 题目描述 N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<...<Ti>Ti+1>…>TK(1<=i<=K). 你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形. 输入输出格

RQNOJ PID192 梦幻大PK [2017年6月计划 二分图02]

PID192 / 梦幻大PK ☆ 提交你的代码 查看讨论和题解 你还木有做过哦 我的状态 查看最后一次评测记录 质量 7 题目评价 质量 7 ★★★★★ ★★★★☆ ★★★☆☆ ★★☆☆☆ ★☆☆☆☆ 50% 0% 25% 0% 25% ★ ★ ★ ★ ☆ 通过人数 754 / 2273 通过统计 最短耗时 0ms 最小内存 0KB 匹配 题目标签 类型 匹配 题目描述 难得到了生日,正逢上班里面一年一度的梦幻大PK,分2组对拼.但是由于某种原因,参加PK的第1组中有些人不能和第2组人PK.可能

ZOJ3195 Design the city [2017年6月计划 树上问题04]

Design the city Time Limit: 1 Second      Memory Limit: 32768 KB Cerror is the mayor of city HangZhou. As you may know, the traffic system of this city is so terrible, that there are traffic jams everywhere. Now, Cerror finds out that the main reason