倍增算法就是根据一个数的往上2^n个祖先等于这个数往上的第2^n-1个祖先的第2^n-1个祖先,然后就用rmq预处理。
这一步要打深搜。
void dfs (int h ,int deepth){
p [h] = 1 ;
for ( int i = Begin [h] ; i ; i = Next[i]){
if ( !p[to[i]] ){
deep[to[i]] = deepth + 1;
dp[to[i]] [0] = h;//记录的是to[i]的父亲结点
dfs (to[i] , deep[to[i]]);
}
}
}
再:
void rmq (int cnt){
int m = cnt;
cnt = log (cnt) / log (2) ;
for(int j = 1 ;j <= cnt ; j ++ ){
for ( int i = 1 ;i <= m ;i ++){
if(dp[i][j - 1] != 0 && dp[dp[i][j-1]][j-1]!=0)
dp [i][j] = dp [ dp[i][j - 1] ][j - 1];
}
}
}
在查找最近公共祖先的时候再先把两个点提到同一深度,此时若处于同一位置,则返回这个位置的节点编号否则,不断的在不超过最近公共祖先的情况下往这个最近公共祖先逼近
int chaxun (int x,int y){
int d1 = deep[x];
int d2 = deep[y];
if( deep[x] < deep[y]){
swap (x,y);
swap (d1,d2);
}
int i;
for ( i = 0; (1 << i) <= d1; i ++ );
-- i;
int j;
for( j = i ;j >= 0 ;j -- ){
if(d1 - (1<<j) >= d2){
x = dp[x][j];
d1 = d1 - (1<<j);
}
}
if ( x == y ) return x;
for( j = i ;j >= 0;j --){
if( dp[x][j] != 0 && dp[x][j] != dp[y][j]/*也就是不超过*/){
x = dp[x][j];
y = dp[y][j];
}
}
return dp[x][0];
//最后返回的是这个比的最近的点的父亲结点的值
}
至于st算法就先放段代码吧:
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1000100;
int Begin [maxn*2], Next[maxn*2],to[maxn*2];
int e;
bool p[maxn];
int root[maxn*2],first[maxn*2],deep[maxn*2];
int dp[maxn][49];
void add(int x,int y){
to[++e]=y;
Next[e]=Begin[x];
Begin[x]=e;
}
int cnt;
void st(int n){
int i,j;
for( i = 1;i <= n ;i ++ ){
dp[i][0]=i;
}
int k = (int) (log((double)(n)) / log(2.0));
for(i = 1 ;i <= k; i ++){
for ( j = 1;j <= n;j ++ ){
if(j + (1<<i-1) > n)continue;
if( deep[dp[j][i-1] ] < deep[dp[ j + (1<<i-1) ][i-1]] )
dp[j][i]=dp[j][i-1];
else dp[j][i] = dp[j+ (1<<i-1) ][i - 1];
}
}
}
int rmq( int x,int y ){
if(x>y){
int temp = x;
x = y;
y = temp;
}
int k = (int)(log ((double)(y-x+1))/ log(2.0));
int a = dp[x][k];
int b = dp[y-(1<<k)+1][k];
if(deep[a] > deep[b])return root[b];
else return root[a];
}
void dfs(int h,int deepth){
p[h]=1,root[++cnt]=h,deep[cnt]=deepth,first[h]=cnt;
for(int i = Begin[h] ; i ; i = Next[i]){
if( ! p[to[i]] ){
dfs(to[i] , deepth + 1);
root[ ++ cnt ] = h;
deep[cnt] = deepth ;
}
}
}
int main(){
int i,j,k,m,n,x,y;
scanf("%d%d%d",&m,&n,&k);
for(i=1;i<=m-1;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(k,1);
st(cnt);
for( i = 1;i <= n ;i ++ ){
scanf("%d%d",&x,&y);
printf("%d\n",rmq(first[x],first[y]));
}
return 0;
}