LCA(最近公共祖先)——dfs+ST 在线算法

一、前人种树

博客:浅谈LCA的在线算法ST表

 

二、沙场练兵

题目:POJ 1330 Nearest Common Ancestors

题解博客:http://www.cnblogs.com/Missa/archive/2012/10/01/2709889.html

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/*
 * LCA  (POJ 1330)
 * 在线算法 DFS + ST
 */
const int MAXN = 10010;
int rmq[2*MAXN];//rmq数组,就是欧拉序列对应的深度序列
struct ST
{
  int mm[2*MAXN];
  int dp[2*MAXN][20];//最小值对应的下标
  void init(int n)
  {
    mm[0] = -1;
    for(int i = 1;i <= n;i++)
    {
      mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
      dp[i][0] = i;
    }
    for(int j = 1; j <= mm[n];j++)
      for(int i = 1; i + (1<<j) - 1 <= n; i++)
        dp[i][j] = rmq[dp[i][j-1]] <
rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
  }
  int query(int  a,int b)//查询[a,b]之间最小值的下标
  {
    if(a > b)swap(a,b);
    int k = mm[b-a+1];
    return rmq[dp[a][k]] <=
rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
  }
};
//边的结构体定义
struct Edge
{
  int to,next;
};
Edge edge[MAXN*2];
int tot,head[MAXN];
  
int F[MAXN*2];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始
int P[MAXN];//P[i]表示点i在F中第一次出现的位置
int cnt;
  
ST st;
void init()
{
  tot = 0;
  memset(head,-1,sizeof(head));
}
void addedge(int  u,int  v)//加边,无向边需要加两次
{
  edge[tot].to = v;
  edge[tot].next = head[u];
  head[u] = tot++;
}
void dfs(int u,int pre,int dep)
{
  F[++cnt] = u;
  rmq[cnt] = dep;
  P[u] = cnt;
  for(int i = head[u];i != -1;i = edge[i].next)
  {
    int v = edge[i].to;
    if(v == pre)continue;
    dfs(v,u,dep+1);
    F[++cnt] = u;
    rmq[cnt] = dep;
  }
}
void LCA_init(int  root,int  node_num)//查询LCA前的初始化
{
  cnt = 0;
  dfs(root,root,0);
  st.init(2*node_num-1);
}
int query_lca(int  u,int v)//查询u,v的lca编号
{
  return F[st.query(P[u],P[v])];
}
bool flag[MAXN];
int main()
{
    int T;
  int N;
  int u,v;
  scanf("%d",&T);
  while(T--)
  {
    scanf("%d",&N);
    init();
    memset(flag,false,sizeof(flag));
    for(int i = 1; i < N;i++)
    {
      scanf("%d%d",&u,&v);
      addedge(u,v);
      addedge(v,u);
      flag[v] = true;
    }
    int root;
    for(int i = 1; i <= N;i++)
      if(!flag[i])
      {
        root = i;
        break;
      }
    LCA_init(root,N);
    scanf("%d%d",&u,&v);
    printf("%d\n",query_lca(u,v));
  }
    return 0;
}
posted @   GGBeng  阅读(1078)  评论(0编辑  收藏  举报
编辑推荐:
· 分享一个我遇到过的“量子力学”级别的BUG。
· Linux系列:如何调试 malloc 的底层源码
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
阅读排行:
· 历时 8 年,我冲上开源榜前 8 了!
· 物流快递公司核心技术能力-海量大数据处理技术
· 四大AI编程工具组合测评
· 关于能否用DeepSeek做危险的事情,DeepSeek本身给出了答案
· 如何在 Github 上获得 1000 star?
点击右上角即可分享
微信分享提示