图论--倍增lca(一直没写代码实现)

如题,原来听了怎么实现,一直没有写过,然后这是提高里会出现的,于是来补一下(好像我要补的还很多啊^_^)
给大家放一道题:洛谷 P3379 【模板】最近公共祖先(LCA)
温馨提示:这题卡常^_^
代码:(具体看注释)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
inline void read(int &x){//据说这是最快的读入
    char ch=' ';
    while(!isdigit(ch=getchar()));
    x=ch-'0';
    while(isdigit(ch=getchar())){
        x=x*10+ch-'0';
    }
}
int n,m,s;
struct edge{//邻接表存储,卡常用
    int to,next;
}e[1000001];//无向图开两倍
//st[k][i]代表从i跳2^k步可以跳到的位置
int st[20][500001],dep[500001],head[500001];//st表,深度,还有邻接表
inline void dfs(int x,int fa,int d){//dfs初始化父亲和深度
    st[0][x]=fa;
    dep[x]=d;
    for(register int i=head[x];i;i=e[i].next){//register卡常,以下省略
        if(e[i].to!=fa)dfs(e[i].to,x,d+1);
    }
}
void getst(){初始化st表
    dfs(s,0,1);//dfs初始化
    for(register int k=0;k<19;k++){
        for(register int i=1;i<=n;i++){
            st[k+1][i]=st[k][st[k][i]];//解释一下这步:先跳2^k步,再跳2^k步,一共就跳了2^(k+1)步
        }
    }
}
inline int lca(int x,int y){
    if(dep[x]>dep[y]){//保证y的深度较大
        swap(x,y);
    }
    for(register int k=19;k>=0;k--){
        if(dep[st[k][y]]>=dep[x]){//如果跳不超过,就跳
            y=st[k][y];
        }
    }
    if(x==y)return x;
    for(register int k=19;k>=0;k--){
        if(st[k][x]!=st[k][y]){//如果跳不超过,就跳
            x=st[k][x];
            y=st[k][y];
        }
    }
    return st[0][x];//这时一定只需要再跳一步了
}
int tot;
inline void addedge(int x,int y){//inline优化
    tot++;
    e[tot].to=y;
    e[tot].next=head[x];
    head[x]=tot;
}
int main(){
    read(n);
    read(m);
    read(s);
    for(register int i=1;i<=n-1;i++){
        int x,y;
        read(x);
        read(y);
        addedge(x,y);
        addedge(y,x);
    }
    getst();
    for(register int i=1;i<=m;i++){
        int x,y;
        read(x);
        read(y);
        printf("%d\n",lca(x,y));
    }
    return 0;
}
posted @ 2017-08-20 22:16  玫葵之蝶  阅读(109)  评论(0编辑  收藏  举报