LCA回顧(主要針對倍增算法)

這個有兩種方法:數組

1、倍增

就是維護一個節點的第\(2^0,\ 2^1,\ 2^2\ ...\)層父親,這樣的話咱們在後面查詢的時候就能夠直接「跳」着找。spa

void pushup()
{
    step=log(maxd*1.0)/log(2.0);

    for(int i=1;i<=step;i++)
        for(int p=1;p<=n;p++) if( fa[p][i-1] ) fa[p][i]=fa[ fa[p][i-1] ][i-1];

    return;
}

而後查詢的時候,先讓兩個點跳到同一深度code

因此要讓較深的一個點先往上跳:class

if( dep[x]<dep[y] ) swap(x,y);
for(int i=step;i>=0;i--) if( dep[x]-(1<<i)>=dep[y] ) x=fa[x][i];

第二行至關於將\(dep(x)-dep(y)\)的值作二進制拆分二進制


跳到同一深度以後,若是兩個節點已經跳到同一個位置,就直接退出。方法

不然,就要繼續同時往上跳,可是,在跳的時候要保證:它們各自跳到的位置必須是不同的!否則的話它們可能都跳到了\(LCA\)的上面!查詢

整個功能段見下(省略了建圖部分):top

struct LCA
{
    int fa[maxn][22],dep[maxn];
    int maxd;
    
    void dfs(int x,int f,int d)
    {
        fa[x][0]=f,dep[x]=d;
        maxd=max( maxd,d );
        
        for(int i=G.Head[x];i;i=G.Next[i])
        {
            Graph::Edge e=G.edges[i];
            if( e.to==f ) continue;
            
            dfs(e.to,x,d+1);
        }
        
        return;
    }
    
    int step;
    
    void pushup()
    {
        step=log(maxd*1.0)/log(2.0);
        
        for(int i=1;i<=step;i++)
            for(int p=1;p<=n;p++) if( fa[p][i-1] ) fa[p][i]=fa[ fa[p][i-1] ][i-1];
        
        return;
    }
    
    int LCA(int x,int y)
    {
        if( dep[x]<dep[y] ) swap(x,y);
        
        for(int i=step;i>=0;i--) if( dep[x]-(1<<i)>=dep[y] ) x=fa[x][i];
        if( x==y ) return y;
        
        for(int i=step;i>=0;i--)
            if( fa[x][i]!=fa[y][i] ) x=fa[x][i],y=fa[y][i];
        
        return fa[x][0];
    }
}SOL;

2、樹鏈剖分

這個更簡單,用\(top\)數組直接跳就好了……co

相關文章
相關標籤/搜索