整理一些树的,基本的,简单的一些知识。

先写一下关于树的许多定义。

树,父节点、子节点、子树、祖先、兄弟、根节点、叶节点、直径、路径、重心、直径、最近公共祖先、生成树、dfs序,树形dp等

 

1、最近公共祖先

一般用倍增求LCA(Least Common Ancestors)。

按照朴素的做法,就是深的点跳到同一高度,然后两个点一齐往上跳。跳到同一位置。

这样其实不慢,一般的树,深度为logn,所以这个复杂度可以是logn。但如果树成了一条链,那么复杂度就是O(n)。

而倍增求LCA,和这个思想是一样的,深的点跳到同一高度,然后两个点一齐往上跳。不过它不是一个点一个点的跳,看下面。

对于任何的数字都可以分解成2的次幂相加的形式(7 = 22+21+20,10 = 23+21...),证明也很简单,任何一个十进制都可以分解成二进制表示。

那么对于跳的任何高度都可以用二进制表示(跳7个,7 = 22+21+20,跳10个10 = 23+21),那么我们预处理出每个点往上跳2的次幂的点,所到达的点是谁就好了。

然后和上面一样跳。

这样明显比上面的快。

贴一下代码 luogu3379

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 
 5 using namespace std;
 6 const int N = 1000100;
 7 
 8 struct Edge {
 9     int v,nxt;
10 } e[N];
11 int f[N][25];
12 int deth[N];
13 int head[N];
14 int n,m,s,tot,a,b,d;
15 
16 void add(int u,int v) {
17     tot++;
18     e[tot].v = v;
19     e[tot].nxt = head[u];
20     head[u] = tot;
21 }
22 
23 void dfs(int x) {
24     for (int i=head[x]; i; i=e[i].nxt) {
25         int v = e[i].v;
26         if(!deth[v])
27         {
28             deth[v] = deth[x]+1;
29             f[v][0] = x;
30             dfs(v);
31         }
32     }
33 }
34 
35 void init() {
36     for (int j=1; j<=20; ++j)
37         for (int i=1; i<=n; ++i)
38             f[i][j] = f[f[i][j-1]][j-1];
39 }
40 
41 int lca(int u,int v) {
42     if (deth[u] < deth[v]) swap(u,v);
43     /*for (int i=20; i>=0; --i)
44     {
45         if (deth[f[u][i]] >= deth[v])
46             u = f[u][i];
47     }*/
48     d = deth[u]-deth[v];
49     for (int i=0; i<=20; ++i) {
50         if ((1<<i) & d)
51             u = f[u][i];
52     }
53     if (u==v) return u;
54     for (int i=20; i>=0; --i) {
55         if(f[u][i] != f[v][i]) {
56             u = f[u][i];
57             v = f[v][i];
58         }
59     }
60     return f[u][0];
61 }
62 
63 int main() {
64     scanf("%d%d%d",&n,&m,&s);
65     for (int i=1; i<n; ++i) {
66         scanf("%d%d",&a,&b);
67         add(a,b);
68         add(b,a);
69     }
70     deth[s] = 1;
71     f[s][0] = 0;
72     dfs(s);
73     init();
74     for (int i=1; i<=m; ++i) {
75         scanf("%d%d",&a,&b);
76         printf("%d\n",lca(a,b));
77     }
78     return 0;
79 }
View Code

相关文章: