dfs序 + RMQ = LCA
2015-07-24 13:44
281 查看
dfs序是指你用dfs遍历一棵树时,每个节点会按照遍历到的先后顺序得到一个序号。然后你用这些序号,可以把整个遍历过程表示出来。
![](http://images0.cnblogs.com/blog2015/699367/201507/241931270685814.jpg)
如上图所示,则整个遍历过程为1 2 3 2 4 5 4 6 4 2 1 7 8 7 1
反正按照实现目的不同,dfs序会长得不太一样,比如说为了实现LCA就需要上面形式的dfs序。
用vs[]来保存整个遍历过程。
id[i]用来保存i节点的序号第一次出现在vs[]中时的下标。
这样当询问u,v点的LCA是谁是,你只要找到在vs[id[u]<= i <= id[v]]中最小值即可,那个最小值所对应的节点就是u,v的LCA
而这个过程你可以用RMQ进行预处理,然后O(1)就可以得到。(你应该知道vs[]的总长度为n*2-1)
测试数据:
8
0 1
0 2
1 3
1 4
2 5
4 6
4 7
3
0 4
3 4
6 2
3次询问的答案你画一下即可。hhhhhh(以0号节点为根)
![](http://images0.cnblogs.com/blog2015/699367/201507/241931270685814.jpg)
如上图所示,则整个遍历过程为1 2 3 2 4 5 4 6 4 2 1 7 8 7 1
反正按照实现目的不同,dfs序会长得不太一样,比如说为了实现LCA就需要上面形式的dfs序。
用vs[]来保存整个遍历过程。
id[i]用来保存i节点的序号第一次出现在vs[]中时的下标。
这样当询问u,v点的LCA是谁是,你只要找到在vs[id[u]<= i <= id[v]]中最小值即可,那个最小值所对应的节点就是u,v的LCA
而这个过程你可以用RMQ进行预处理,然后O(1)就可以得到。(你应该知道vs[]的总长度为n*2-1)
#include<bits/stdc++.h> using namespace std; const int M = 1e5 + 10 ; vector<int> g[M] ; int n ; vector<int> vs ;//dfs order int tot ; int orm[M] ; int id[M] ; int dep[M] ; int d[M][30] ;//RMQ void dfs (int o , int u ,int DEP) { int tmp = tot ++ ; dep[u] = DEP ; id[u] = vs.size () ; orm[tmp] = u ; vs.push_back (tmp) ; for (int i = 0 ; i < g[u].size () ; i ++) { int v = g[u][i] ; if (v == o) continue ; dfs (u , v , DEP + 1) ; } int len = vs.size () ; if (vs[len-1] == tmp) vs.push_back (vs[id[o]]) ; else vs.push_back (tmp) ; } void init_RMQ () { for (int i = 0 ; i < 2*n-1 ; i ++) d[i][0] = vs[i] ; for (int j = 1 ; (1 << j) <= n ; j ++) { for (int i = 0 ; i + (1 << j) <= n ; i ++) { d[i][j] = min (d[i][j-1] , d[i+(1<<(j-1))][j-1]) ; } } } int RMQ (int l , int r) { printf ("l = %d , r = %d\n" , l , r ) ; int k = 0 ; while ( (1<<(k+1)) <= r - l + 1) k ++ ; int tmp = min (d[l][k] , d[1+r-(1<<k)][k]) ; return orm[tmp] ; } void Print () { for (int i = 0 ; i < 2*n-1 ; i ++) printf ("%3d " , i ) ; puts ("") ; puts ("dfs order:") ; for (int i = 0 ; i < 2*n-1 ; i ++) printf ("%3d " , vs[i]) ; puts ("") ; puts ("deep:") ; for (int i = 0 ; i < n ; i ++) printf ("%3d " , dep[i]) ; puts ("") ; puts ("id :") ; for (int i = 0 ; i < n ; i ++) printf ("%3d " , id[i]) ; puts ("") ; } void LCA () { dfs (0,0,0) ; init_RMQ () ; Print () ; } int main () { cin >> n ; for (int i = 0 ; i < n - 1 ; i ++) { int u , v ; cin >> u >> v ; g[u].push_back (v) ; g[v].push_back (u) ; } LCA () ; int Q ; cin >> Q ; while (Q --) { int u , v ; cin >> u >> v ; if (id[u] > id[v]) swap (u , v ) ; int ans = RMQ (id[u] , id[v]) ; printf ("The %d and %d the lastest ans is %d , and they are away from %d\n" , u , v , ans , dep[u]+dep[v]-2*dep[ans]) ; } return 0 ; }
测试数据:
8
0 1
0 2
1 3
1 4
2 5
4 6
4 7
3
0 4
3 4
6 2
3次询问的答案你画一下即可。hhhhhh(以0号节点为根)
相关文章推荐
- hdu3397 线段树 成段更新
- SCWS分词扩展在WINDOWS下的安装方法
- 一个简单的多线程题目
- Lowest Common Ancestor of a Binary Tree
- xcode6.4升级以后Alcatraz不能使用的解决办法
- Samba3.0服务器实战调试
- Python正则表达式指南
- hdu 2824 The Euler function
- put和post
- iphone手机屏幕大小
- GIT简单用法
- XAMPP 安装
- 揭秘百度核心技术:53位专家纯干货分享
- mysql union和union all 的区别以及使用
- 结构型模式-亨元模式
- uimsbf和 bslbf的含义
- qt QLineEdit 左侧带自定义图标类
- Android -- 数据库1
- 好压报错“启动参数错误,程序即将退出!”
- Matlab实现单(双)极性(不)归零码