倍增法求树中的LCA 洛谷 P3379模板题

倍增法求树中的LCA

第一次。。我用STL中的vector,然后由两个点TLE了。。。无奈只好选择用链表存边

现附上TLE代码(开O2可过):

#include 
using namespace std;
const int maxn=5e5+7;
int n,m,s;
int lg[maxn],fa[maxn][22],depth[maxn];//fa[i][j],i节点往上2^j的父亲
vector <int> g[maxn];
void dfs(int now,int fath){
    fa[now][0]=fath,depth[now]=depth[fath]+1;
    for(int i=1;i<=lg[depth[now]];i++)//在建树的过程中,把该节点的所有2^0,2^1……上面的节点全部求出来
        fa[now][i]=fa[fa[now][i-1]][i-1];
    for(int i=0;i<g[now].size();i++)//然后接着往下走
    if(g[now][i]!=fath)    
        dfs(g[now][i],now);
}
int LCA(int a,int b){
    if(depth[a]<depth[b])   swap(a,b);//我们需要恒定一个大小关系,方便下一个循环
    while(depth[a]>depth[b])   
        a=fa[a][lg[depth[a]-depth[b]]-1];//使两者的深度相同
    if(a==b)
        return a;
    for(int k=lg[depth[a]]-1;k>=0;k--)//在相同的深度情况下,就可以一起往上面跳了,此处是距离从大到小跳
    if(fa[a][k]!=fa[b][k])//lg[depth[a]]-1==log2(depth[a]),
        a=fa[a][k],b=fa[b][k];//不相等就跳过去
    return fa[a][0];
}
int main(){
    scanf("%d %d %d",&n,&m,&s);
    for(int i=1;i<n;i++){
        int x,y;
        scanf("%d %d",&x,&y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(int i = 1; i <= n; ++i) //预先算出log_2(i)+1的值,用的时候直接调用就可以了
        lg[i] = lg[i-1] + (1 << lg[i-1] == i);
    dfs(s,0);//接着把树建好
    for(int i=1;i<=m;i++){
        int a,b;
        scanf("%d %d",&a,&b);
        printf("%d\n",LCA(a,b));
    }
return 0;
}

用链表存边的(不开O2可过)

#include 
using namespace std;
const int maxn=5e5+7;
int n,m,s,tot=0;
int lg[maxn],fa[maxn][22],depth[maxn];//fa[i][j],i节点往上2^j的父亲
struct op {
    int t, nex;
}e[500010 << 1];
int head[maxn];
vector <int> g[maxn];
void add(int x,int y){
    e[++tot].t = y;
    e[tot].nex = head[x];
    head[x] = tot;
}
void dfs(int now,int fath){
    fa[now][0]=fath,depth[now]=depth[fath]+1;
    for(int i=1;i<=lg[depth[now]];i++)//在建树的过程中,把该节点的所有2^0,2^1……上面的节点全部求出来
        fa[now][i]=fa[fa[now][i-1]][i-1];
     for(int i = head[now]; i; i = e[i].nex)//往下走
        if(e[i].t != fath) dfs(e[i].t, now);
}
int LCA(int a,int b){
    if(depth[a]<depth[b])   swap(a,b);//我们需要恒定一个大小关系,方便下一个循环
    while(depth[a]>depth[b])   
        a=fa[a][lg[depth[a]-depth[b]]-1];//使两者的深度相同
    if(a==b)
        return a;
    for(int k=lg[depth[a]]-1;k>=0;k--)//在相同的深度情况下,就可以一起往上面跳了,此处是距离从大到小跳
    if(fa[a][k]!=fa[b][k])//lg[depth[a]]-1==log2(depth[a]),
        a=fa[a][k],b=fa[b][k];//不相等就跳过去
    return fa[a][0];
}
int main(){
    scanf("%d %d %d",&n,&m,&s);
    for(int i=1;i<n;i++){
        int x,y;
        scanf("%d %d",&x,&y);
        add(x,y);
        add(y,x);
    }
    for(int i = 1; i <= n; ++i) //预先算出log_2(i)+1的值,用的时候直接调用就可以了
        lg[i] = lg[i-1] + (1 << lg[i-1] == i);
    dfs(s,0);//接着把树建好
    for(int i=1;i<=m;i++){
        int a,b;
        scanf("%d %d",&a,&b);
        printf("%d\n",LCA(a,b));
    }
return 0;
}

你可能感兴趣的:(LCA,倍增,洛谷)