模板

倍增lca
预处理每个节点的深度,从节点\(u\)向上跳\(2^k(0\leq k\leq \log n)\)步所能到达的节点编号
预处理时间复杂度\(O(n\log n)\)
查询时间复杂度\(O(\log n)\)

const int maxn=40010;
int depth[maxn],fa[maxn][20];

void dfs(int u,int f){
    fa[u][0]=f;
    for(int i=head[u];~i;i=ne[i]){
        int v=to[i];
        if(v!=f){
            depth[v]=depth[u]+1;
            dfs(v,u);
        }
    }
}

void lca_init(){
    depth[1]=1;
    dfs(1,0);
    for(int j=1;j<20;j++){
        for(int i=1;i<=n;i++){
            fa[i][j]=fa[fa[i][j-1]][j-1];
        }
    }
}

int lca(int x,int y){
    if(depth[x]>depth[y]) swap(x,y);
    int d=depth[y]-depth[x];
    for(int i=0;i<20;i++){
        if((1<<i)&d) y=fa[y][i];
    }
    if(x==y) return x;
    for(int i=19;i>=0;i--){
        if(fa[x][i]!=fa[y][i]){
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    return fa[x][0];
}

模板题:hdu2586 How far away ?
基于rmq的算法
按照从根节点开始的\(dfs\)访问顺序得到顶点序列\(vs[maxn]\),节点深度\(depth[maxn]\),每个节点第一次出现在顶点序列中的下标\(id[maxn]\)
\(id[u]\leq id[v]\),则有:

\[lca(u,v)=vs[id[u]\leq i\leq id[v]中令depth[i]最小的i] \]

可以通过\(rmq\)查询,返回的是下标而不是最值

const int maxn=10010,maxm=20010;
int n,st[2*maxn][15],mini[2*maxn],idx[2*maxn][15];
int vs[2*maxn],depth[2*maxn],id[maxn];

void rmq_init(int n){
    for(int i=1;i<=n;i++){
        st[i][0]=depth[i];
        idx[i][0]=i;
    }
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i+(1<<j)-1<=n;i++){
            if(st[i][j-1]<st[i+(1<<(j-1))][j-1]){
                st[i][j]=st[i][j-1];
                idx[i][j]=idx[i][j-1];
            }
            else{
                st[i][j]=st[i+(1<<(j-1))][j-1];
                idx[i][j]=idx[i+(1<<(j-1))][j-1];
            }
        }
    }
    for(int len=1;len<=n;len++){
        int k=0;
        while((1<<(k+1))<=len) k++;
        mini[len]=k;
    }
}

int rmq_id(int l,int r){
    int k=mini[r-l+1];
    if(st[l][k]<st[r-(1<<k)+1][k]) return idx[l][k];
    return idx[r-(1<<k)+1][k];
}

void dfs(int u,int fa,int dep,int& k){
    id[u]=k;
    vs[k]=u;
    depth[k++]=dep;
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];
        dfs(v,u,dep+1,k);
        vs[k]=u;
        depth[k++]=dep;
    }
}

void lca_init(int root){
    int k=1;
    dfs(root,-1,0,k);
    rmq_init(2*n-1);
}

int lca(int u,int v){
    return vs[rmq_id(min(id[u],id[v]),max(id[u],id[v]))];
}
posted @ 2020-07-28 00:32  fxq1304  阅读(37)  评论(0编辑  收藏  举报