LCA模板

树链剖分LCA
O(n)-O(logn)

#include<iostream>
#include<cstdio>
const int N=500005;
int n,m,S,ecnt,head[N],tim;
struct Edge{int to,nxt;}e[N<<1];
void add(int bg,int ed){e[++ecnt].nxt=head[bg];e[ecnt].to=ed;head[bg]=ecnt;}
int fa[N],dfn1[N],top[N],dfn2[N],son[N],dep[N],siz[N],rnk[N];
void dfs1(int x){
    siz[x]=1;
    dep[x]=dep[fa[x]]+1;
    for(int i=head[x],v;i;i=e[i].nxt){v=e[i].to;
        if(v==fa[x]) continue;
        
        fa[v]=x;
        dfs1(v);
        siz[x]+=siz[v];
        if(siz[son[x]]<siz[v]) son[x]=v;
    }
}
void dfs2(int x,int qtop){
    top[x]=qtop;
    dfn1[x]=++tim;
    rnk[tim]=x;
    if(son[x]) dfs2(son[x],qtop);
    for(int i=head[x];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa[x]||v==son[x])continue;
        dfs2(v,v);
    }
    dfn2[x]=tim;
}
int main(){
    scanf("%d%d%d",&n,&m,&S);
    for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
    dfs1(S);dfs2(S,S);
    for(int i=1,x,y;i<=m;i++){
        scanf("%d%d",&x,&y);
        while(top[x]!=top[y]){
            if(dep[top[x]]>=dep[top[y]]) x=fa[top[x]];
            else y=fa[top[y]];
        }
        printf("%d\n",dep[x]<dep[y]?x:y);
    }
}

tarjan flag++;

倍增 O(nlogn)-O(logn)

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=1000005;
int n,q,nxt[N],to[N],fa[N][25],ecnt,head[N],dep[N],S;
inline void add(int bg,int ed) {nxt[++ecnt]=head[bg];to[ecnt]=ed;head[bg]=ecnt;}
void dfs(int x,int f) {
    fa[x][0]=f;dep[x]=dep[f]+1;
    for(int i=1;i<=24;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=head[x];i;i=nxt[i]) {
        if(to[i]==f) continue;
        dfs(to[i],x);
    }
}
int lca(int x,int y) {
    if(x==y) return x;
    if(dep[x]<dep[y])swap(x,y);
    for(int i=24;~i;i--) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
    //cout<<dep[x]<<' '<<dep[y]<<endl;
    if(x==y) return x;
    for(int i=24;~i;i--) 
        if(fa[x][i]!=fa[y][i]) 
        x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
int main() {
    scanf("%d%d%d",&n,&q,&S);
    for(int i=1,x,y;i<n;i++)  scanf("%d%d",&x,&y),add(x,y),add(y,x);
    dfs(S,0);
    int x,y;
    while(q--) {
        scanf("%d%d",&x,&y);
    	printf("%d\n",lca(x,y));
    }
} 

RMQ+欧拉序 O(logn)-O(1)

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=1000005;
int n,q,nxt[N],to[N],val[N],Min[25][N],ecnt,head[N],tim,dep[N],rnk[N],dfn[N],S,node[25][N];
inline void add(int bg,int ed) {nxt[++ecnt]=head[bg];to[ecnt]=ed;head[bg]=ecnt;}
void dfs(int x,int f) {
    dep[x]=dep[f]+1;dfn[x]=++tim;Min[0][tim]=dep[x];node[0][tim]=x;
    for(int i=head[x];i;i=nxt[i]) {
        if(to[i]==f) continue;
        dfs(to[i],x);
        Min[0][++tim]=dep[x];node[0][tim]=x;
    }
}
void ask(int x,int y) {
    if(x>y) swap(x,y);
    int k=log2(y-x+1);
    if(Min[k][x]<Min[k][y-(1<<k)+1]) printf("%d\n",node[k][x]);
    else printf("%d\n",node[k][y-(1<<k)+1]);
    return ;
}
int main() {
    scanf("%d%d%d",&n,&q,&S);
    for(int i=1,x,y;i<n;i++)  scanf("%d%d",&x,&y),add(x,y),add(y,x);
    dfs(S,0);
    for(int i=1;(1<<i)<=tim;i++) {
        for(int j=1;j+(1<<i)-1<=tim;j++) {
            if(Min[i-1][j]<Min[i-1][j+(1<<i-1)]) {
                Min[i][j]=Min[i-1][j];
                node[i][j]=node[i-1][j];
            }
            else {
                Min[i][j]=Min[i-1][j+(1<<i-1)];
                node[i][j]=node[i-1][j+(1<<i-1)];
            }
        }
    }
    int x,y;
    while(q--) {
        scanf("%d%d",&x,&y);
        ask(dfn[x],dfn[y]);
    }
} 
posted @ 2018-07-08 18:41  SWHsz  阅读(101)  评论(0编辑  收藏  举报