您的位置:首页 > 其它

dfs序 + RMQ = LCA

2015-07-24 13:44 281 查看
dfs序是指你用dfs遍历一棵树时,每个节点会按照遍历到的先后顺序得到一个序号。然后你用这些序号,可以把整个遍历过程表示出来。



如上图所示,则整个遍历过程为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号节点为根)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: