LCA之倍增及ST算法

倍增算法就是根據一個數的往上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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章