LCA之倍增及ST算法

来源:互联网 发布:mac git 添加忽略文件 编辑:程序博客网 时间:2024/04/29 16:50

倍增算法就是根据一个数的往上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;}
1 0