参见topcoder的算法教程,Range Minimum Query and Lowest Common Ancestor
JOJ 一个题目:
2408 Beautiful girl, 题意:一颗树,给定三个顶点A、B、C,判断A与B之间的路径是否可以经过C
代码:
代码
/*
* LCA->RMQ
*/
#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;
#define MY_MAX 50010
vector<int> graph[MY_MAX];
void read(int n){
int i, u, v;
for(i=0; i<n; ++i)
if(!graph[i].empty())
graph[i].clear();
for(i=1; i<n; ++i){
scanf("%d %d", &u, &v);
graph[u].push_back(v);
graph[v].push_back(u);
}
}
int E[MY_MAX*2];//E[i] is the label of i-th visited node in the tour
int L[MY_MAX*2];//L[i] is the level of node E[i]
int H[MY_MAX]; //the index of the first occurrence of node i in E
bool visited[MY_MAX];
void DFS(int u, int d, int &k){
visited[u] = true;
E[k] = u;
L[k] = d;
H[u] = k;
++k;
int v;
for(size_t i=0; i<graph[u].size(); ++i){
v = graph[u][i];
if(!visited[v]){
DFS(v, d+1, k);
E[k] = u;
L[k] = d;
++k;
}
}
}
int M[MY_MAX*2][20]; //存储的索引
void preprocess(int a[], int n){
int i, j;
//initialize for the intervals with length 1
for(i=0; i<n; ++i)
M[i][0] = i;
//compute values from smaller to bigger intervals
for(j=1; 1<<j <= n; ++j){
for(i=0; i + (1<<j) - 1 < n; ++i)
if(a[M[i][j - 1]] < a[M[i + (1<<(j-1))][j-1]])
M[i][j] = M[i][j-1];
else
M[i][j] = M[i + (1<<(j-1))][j-1];
}
}
int RMQ(int a[], int i, int j){
if(i > j)
swap(i, j);
int k;
k = int(log(j-i+1) / log(2.0));
if(a[M[i][k]] < a[M[j - (1<<k) + 1][k]])
return M[i][k];
else
return M[j - (1<<k) + 1][k];
}
int main(){
// freopen("in", "r", stdin);
int n, m, k, case_num = 1;
while(scanf("%d", &n) != EOF){
read(n);
for(k=0; k<n; ++k)
visited[k] = false;
k = 0;
DFS(0, 0, k);
preprocess(L, 2*n-1);
int a, b, c;
int lab, lac, lbc;
if(case_num != 1)
printf("\n");
printf("Case %d:\n", case_num++);
scanf("%d", &m);
for(k=0; k<m; ++k){
scanf("%d %d %d", &a, &b, &c);
lab = E[RMQ(L, H[a], H[b])];
lac = E[RMQ(L, H[a], H[c])];
lbc = E[RMQ(L, H[b], H[c])];
if(a == c || b == c || (lab == lac && lbc == c)
|| (lab == lbc && lac == c))
printf("Yes\n");
else
printf("No\n");
}
}
}