LCA(最近公共祖先)——dfs+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; } |
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个我遇到过的“量子力学”级别的BUG。
· Linux系列:如何调试 malloc 的底层源码
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 历时 8 年,我冲上开源榜前 8 了!
· 物流快递公司核心技术能力-海量大数据处理技术
· 四大AI编程工具组合测评
· 关于能否用DeepSeek做危险的事情,DeepSeek本身给出了答案
· 如何在 Github 上获得 1000 star?