【模板】最近公共祖先

倍增爬

#include<iostream>
#include<cstdio>

#define ri register int
#define u int

namespace opt {

    inline u in() {
        u x(0),f(1);
        char s(getchar());
        while(s<'0'||s>'9') {
            if(s=='-') f=-1;
            s=getchar();
        }
        while(s>='0'&&s<='9') {
            x=(x<<1)+(x<<3)+s-'0';
            s=getchar();
        }
        return x*f;
    }

}

using opt::in;

#define NN 500005

#include<cstring>
#include<algorithm>
#include<cmath>

namespace mainstay {
    
    u N,M,S,cnt,mxd,fa[NN][20],d[NN],h[NN];
    
    struct node{
        u to,next;
    }a[NN<<1];
    
    inline void add(const u &x,const u &y){
        a[++cnt].next=h[x],a[cnt].to=y,h[x]=cnt;
    }
    
    void dfs(const u &x,const u &prt,const u &deep){
        fa[x][0]=prt,d[x]=deep,mxd=std::max(mxd,deep);
        for(ri i(h[x]);i;i=a[i].next){
            u _y(a[i].to);
            if(_y^prt){
                dfs(_y,x,deep+1);
            }
        }
    }
    
    inline void pri(){
        for(ri j(1);mxd-(1<<j)>=1;++j){
            for(ri i(1);i<=N;++i){
                fa[i][j]=fa[fa[i][j-1]][j-1];
            }
        }
    }
    
    u climb(const u &x,const u &y){
        u a(x),b(y);
        if(d[a]>d[b]) std::swap(a,b);
        u k(std::log(d[b])/std::log(2));
        for(ri i(k);i>=0;--i) if(d[fa[b][i]]>=d[a]) b=fa[b][i];
        if(a==b) return a;
        for(ri i(k);i>=0;--i){
            if(fa[a][i]^fa[b][i]){
                a=fa[a][i],b=fa[b][i];
            }
        }
        return fa[a][0];
    }

    inline void solve() {
        N=in(),M=in(),S=in();
        for(ri i(1);i<N;++i){
            u _a(in()),_b(in());
            add(_a,_b),add(_b,_a);
        }
        dfs(S,0,1),pri();
        for(ri i(1);i<=M;++i){
            u _a(in()),_b(in());
            printf("%d\n",climb(_a,_b));
        }
    }

}

int main() {

    //freopen("x.txt","r",stdin);
    mainstay::solve();

}

 

posted @ 2019-11-15 20:35  pai_hoo  阅读(101)  评论(0编辑  收藏  举报