LCA + 二分

两个最近的点u和v的最近的公共的祖先称为最近公共祖先(LCA)。普通的LCA算法,每算一次LCA的时间复杂度为线性o(n);

这里讲LCA + 二分的方法。首先对于任意的节点v,利用其父节点的信息,可以通过par2[v]=par[par[v]]得到向上走两步的节点。依此信息可以通过par4[v]=par2[par2[v]]得到向上走4步的节点。所以,根据此方法可以得到向上走2^k所得到的节点par[k][v]。每次搜索的复杂度为o(log n),预处理par[k][v]的复杂度为o(nlog n)。(我觉得挑战程序设计LCA部分写的挺明白的)

模版代码如下:

 1 //LCA + 二分
 2
 3 vector <int> G[MAX_V]; //邻接表
 4 int root; //根的编号
 5
 6 int par[MAX_LOG_V][MAX_V]; // 向上走2^k所到的父节点编号(根节点的父节点为-1)
 7 int dep[MAX_V]; //节点的深度
 8
 9 void dfs(int v , int p , int d) { //3个参数分别表示 当前节点 父节点 深度
10     par[v][0] = p;
11     dep[v] = d;
12     for(int i = 0 ; i < G[v].size() ; i++) {
13         dfs(G[v][i] , v , d + 1);
14     }
15 }
16 //预处理
17 void init(int n) {
18     dfs(root , -1 , 0); //预处理出par[0]和dep
19     for(int k = 0 ; k + 1 < MAX_LOG_V ; k++) {
20         for(int v = 1 ; v <= n ; v++) {
21             if(par[k][v] < 0)
22                 par[k + 1][v] = -1; //v向上的2 ^ (k + 1)的节点超过根节点
23             else
24                 par[k + 1][v] = par[k][par[k][v]]; //v向上的2^k的节点 又向上的2^k个节点,所以是向上2^(k + 1)个节点
25         }
26     }
27 }
28 //计算u和v的LCA
29 int lca(int u , int v) {
30     if(dep[u] < dep[v]) //让u和v向上走到同一深度
31         swap(u , v);
32     for(int k = 0 ; k < MAX_LOG_V ; k++) {
33         if((dep[v] - dep[u]) >> k & 1) { //把深度差化为2进制(快速幂原理) 依次从低位相减
34             v = par[k][v];
35         }
36     }
37     if(u == v) //要是节点相同则输出LCA
38         return u;
39     for(int k = MAX_LOG_V - 1 ; k >= 0 ; k--) { //二分搜索计算LCA
40         if(par[k][u] != par[k][v]) {  //若他们的2^k节点不相同 则u和v向上移动,一直移动直到他们的上一个节点相同
41             u = par[k][u];
42             v = par[k][v];
43         }
44     }
45     return par[0][u];
46 }
时间: 2024-12-24 19:00:54

LCA + 二分的相关文章

noip 2015 运输计划 (lca+二分)

/* 95 最后一个点T了 qian lv ji qiong 了 没学过树剖 听chx听xzc说的神奇的方法 Orz 首先求出每个计划的路径长度 这里写的倍增 然后二分答案 对于每个ans 统计>他的路径条数 tot 并维护最大差值 dec 并且对于每条不合法的路径维护每个点的经过次数 然后枚举点 如果经过次数==tot说明每一条不合法的都经过他 然后尝试把它建成虫洞 如果他对应边的权值>=dec 那么我们删掉它ans就合法了 关键是统计每个点在非法路径中的经过次数 : 维护sum数组 对于每

[NOIP2015]运输计划 D2 T3 LCA+二分答案+差分数组

[NOIP2015]运输计划 D2 T3 Description 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有星球. 小P掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从ui号星球沿最快的宇航路径飞行到vi号星球去.显然,飞船驶过一条航道是需要时间的,对于航道j,任意飞船驶过它所花费的时间为tj,并且任意两艘飞船之间不会产生任何干扰. 为了鼓励科技创新,L国国王同意小P的物流

hdu3830(lca + 二分)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3830 题意: 有三个点 a, b, c, 对于其中任意一点 x 可以跨过一个点移动到另一个位置, 当且仅当移动前后的 x 与其所跨越的点的距离相等 .给出两组点, 问其能否相互到达, 若能并输出最少需要移动多少步 . 思路: http://www.cnblogs.com/scau20110726/archive/2013/06/14/3135024.html 代码: 1 #include <ios

二分算法~~~大综合

二分:一个非常神奇的算法:永远记住二分,分的是答案,直接在答案在的区间范围中二分,分出一个值,就判断是不是           答案,并进行转移 二分答案: 如果已知候选答案的范围[min,max],有时候我们不必通过计算得到答案,只需在此范围内应用“二分”的过程,逐渐靠近答案(最后,得到答案)! 一.何时可以使用“二分答案” 不是任何题目都适合使用“二分答案”的,我Sam观察到一般有以下的一些特征: A. 候选答案必须是离散的 ,且已知答案的范围是:[最小值min, 最大值max] (连续区间

NOIP 2015 BZOJ 4326 运输计划 (树链剖分+二分)

题目大意:给一棵带有边权的树,有m条路径,可以使一条边的权值为0,求最远路径的最小值.题解:因为题目的数据点给的很明确 因此可以打n*n的去骗前五十分.另外m=1时可以特判另外打个程序骗60分.60分程序: #include<cstdio> #include<algorithm> int dep[100001],fa[100001],last[200001],next[200001],e[200001],val[200001],cost[100001],tot,a,b,vv,u[1

[填坑][主线任务]历年NOIP刷题计划

今天又是喜闻乐见的非考试日,那么今天做点什么呢== 前些日子的主线任务陆陆续续(接近)完成了,好多蒙蔽的没学好的算法都算是入门补坑了 我听学长说,做题的顺序是:NOIP真题->NOIP模拟题->专项练习->杂题 啊哈!最重要的真题我还没做几道呢...于是这两天填填这个坑吧 [NOIP2016 Day1 T2]天天爱跑步 NOIP2016最难的题没有之一QAQ,原来做过一直没过,今天重新听讲解,总算打了出来 [NOIP2015 Day2 T3]运输计划 压轴题防AK,最后一个点及其凶残,并

BZOJ 4326:NOIP2015 运输计划(二分+差分+lca)

NOIP2015 运输计划Description公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去.显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰.为了鼓励科技创新, L

NOIP2015 运输计划(二分+LCA+差分)

4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 308  Solved: 208[Submit][Status][Discuss] Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui

NOIp2015 运输计划 [LCA] [树上差分] [二分答案]

我太懒了 吃掉了题面 题解 & 吐槽 一道很好的树上差分练习题. 不加fread勉强a过bzoj和luogu的数据,加了fread才能在uoj里卡过去. 可以发现,答案则是运输计划里花费的最大值,最大值最小,便是二分答案的标志. 那么该怎么check呢... 我们得找出所有超过限制的计划,这个过程可以在LCA倍增的过程中预处理出来. 然后再找出一些被这些计划都覆盖的边,找到最大的那条边,如果最大的计划花费减去最大的那条边小于x,那么x就是可行的. 但是该怎么找到那些被计划都覆盖的边呢... 我们