算法模板——LCA(最近公共祖先)
时间:2022-05-07
本文章向大家介绍算法模板——LCA(最近公共祖先),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
实现的功能如下——在一个N个点的无环图中,共有N-1条边,M个访问中每次询问两个点的距离
原理——既然N个点,N-1条边,则说明这是一棵树,而且联通。所以以1为根节点DFS建树,然后通过求两点的LCA的方式,先求得最近公共祖先,然后再通过深度来求出两点距离
1 type
2 point=^node;
3 node=record
4 g:longint;
5 next:point;
6 end;
7 const
8 maxn=100500;
9 maxm=trunc(ln(maxn)/ln(2))+1;
10 var
11 i,j,k,l,m,n:longint;
12 a:array[0..maxn] of point;
13 c:array[0..maxm,0..maxn] of longint;
14 d:array[0..maxn] of longint;
15 function max(x,y:longint):longint;inline;
16 begin
17 if x>y then max:=x else max:=y;
18 end;
19 function min(x,y:longint):longint;inline;
20 begin
21 if x<y then min:=x else min:=y;
22 end;
23 procedure swap(var x,y:longint);inline;
24 var z:longint;
25 begin
26 z:=x;x:=y;y:=z;
27 end;
28 procedure add(x,y:longint);inline;
29 var p:point;
30 begin
31 new(p);p^.g:=y;
32 p^.next:=a[x];a[x]:=p;
33 end;
34 procedure dfs(x:longint);inline;
35 var p:point;
36 begin
37 p:=a[x];
38 while p<>nil do
39 begin
40 if c[0,p^.g]=0 then
41 begin
42 c[0,p^.g]:=x;
43 d[p^.g]:=d[x]+1;
44 dfs(p^.g);
45 end;
46 p:=p^.next;
47 end;
48 end;
49 function getfat(x,y:longint):longint;inline;
50 var i,j,k:longint;
51 begin
52 i:=0;
53 while y>0 do
54 begin
55 if odd(y) then x:=c[i,x];
56 inc(i);y:=y div 2;
57 end;
58 exit(x);
59 end;
60 function getcom(x,y:longint):longint;inline;
61 var i:longint;
62 begin
63 if d[x]<d[y] then swap(x,y);
64 x:=getfat(x,d[x]-d[y]);
65 if x=y then exit(x);
66 for i:=maxm downto 0 do
67 begin
68 if c[i,x]<>c[i,y] then
69 begin
70 x:=c[i,x];
71 y:=c[i,y];
72 end;
73 end;
74 exit(c[0,x]);
75 end;
76
77 begin
78 readln(n,m);
79 for i:=1 to n do a[i]:=nil;
80 for i:=1 to n-1 do
81 begin
82 readln(j,k);
83 add(j,k);add(k,j);
84 end;
85 fillchar(d,sizeof(d),0);
86 fillchar(c,sizeof(c),0);
87 c[0,1]:=-1;
88 dfs(1);
89 for i:=1 to maxm do
90 for j:=1 to n do
91 c[i,j]:=c[i-1,c[i-1,j]];
92 for i:=1 to m do
93 begin
94 readln(j,k);
95 l:=getcom(j,k);
96 writeln(d[j]+d[k]-d[l]-d[l]);
97 end;
98 readln;
99 end.
100
- 高通GPIO驱动(DTS方式)
- Dos烧录脚本
- 使用ServiceStack构建Web服务
- 《Redis设计与实现》读书笔记(二十三) ——Redis服务器初始化
- 警惕:Oracle中删除的分区不会进入回收站(Recyclebin)
- 《Redis设计与实现》读书笔记(二十五) ——Redis主从复制具体过程
- 基于input子系统的sensor驱动调试(一)
- 《Redis设计与实现》读书笔记(二十六) ——Redis哨兵(sentinel)启动与建立监听机制
- 《Redis设计与实现》读书笔记(二十七) ——Redis哨兵(sentinel)主服务器下线判断与故障转移
- 基于input子系统的sensor驱动调试(二)
- 编程语言中的闭包
- 《Redis设计与实现》读书笔记(二十八) ——Redis集群节点结构与槽分配
- Linux RCU 机制详解
- 《Redis设计与实现》读书笔记(二十九) ——Redis集群执行命令与重新分片
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法