LCA 倍增||树链剖分

Posted Candy?

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCA 倍增||树链剖分相关的知识,希望对你有一定的参考价值。

方法1:倍增

1498ms

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=5e5+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    return x*f;
}
int n,q,root,a,b;
struct edge{
    int v,ne;
}e[N<<1];
int cnt=0,h[N];
inline void ins(int u,int v){
    cnt++;
    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt;
}
int fa[N][21],deep[N],vis[N];
void dfs(int u){
    vis[u]=1;
    for(int j=1;(1<<j)<=deep[u];j++)
        fa[u][j]=fa[fa[u][j-1]][j-1];
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v;
        if(vis[v]) continue;
        deep[v]=deep[u]+1;
        fa[v][0]=u;
        dfs(v);
    }
}
int lca(int x,int y){
    if(deep[x]<deep[y]) swap(x,y);
    int bin=deep[x]-deep[y];
    for(int i=0;i<=16;i++)
        if((1<<i)&bin) x=fa[x][i];//,printf("x %d\n",i);
    
    for(int i=16;i>=0;i--)
        if(fa[x][i]!=fa[y][i]){
            x=fa[x][i];
            y=fa[y][i];
        }
    if(x==y) return x;
    else return fa[x][0];
}
int main(int argc, const char * argv[]) {
    n=read();q=read();root=read();
    for(int i=1;i<=n-1;i++) a=read(),b=read(),ins(a,b);
    dfs(root);
    for(int i=1;i<=q;i++){
        a=read();b=read();
        printf("%d\n",lca(a,b));
    }
    return 0;
}

方法2:树链剖分

1314ms

让链首深度大的走到重链的父节点直到在一条重链上,返回深度小的节点

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=5e5+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    return x*f;
}
int n,q,root,a,b;
struct edge{
    int v,ne;
}e[N<<1];
int cnt=0,h[N];
inline void ins(int u,int v){
    cnt++;
    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt;
}
int fa[N],deep[N],mx[N],size[N];
void dfs(int u){
    size[u]++;
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v;
        if(v==fa[u]) continue;
        fa[v]=u;deep[v]=deep[u]+1;
        dfs(v);
        size[u]+=size[v];
        if(size[v]>size[mx[u]]) mx[u]=v;
    }
}
int tid[N],top[N],tot;
void dfs(int u,int anc){
    if(!u) return;
    tid[u]=++tot;top[u]=anc;
    dfs(mx[u],anc);
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v;
        if(v!=fa[u]&&v!=mx[u]) dfs(v,v);
    }
}
int lca(int x,int y){
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    return x;
}
int main(int argc, const char * argv[]) {
    n=read();q=read();root=read();
    for(int i=1;i<=n-1;i++) a=read(),b=read(),ins(a,b);
    dfs(root);
    dfs(root,root);
    for(int i=1;i<=q;i++){
        a=read();b=read();
        printf("%d\n",lca(a,b));
    }
    return 0;
}

 

以上是关于LCA 倍增||树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

树链剖分简(单)介(绍)

LCA—树链剖分求解

树链剖分求LCA

dfs序+RMQ求LCA详解

LCA 树链剖分

树链剖分洛谷P3379 树链剖分求LCA