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