lca模板

一 tarjan算法

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define For(i,j,k) for(register int i=(j);i<=(int)k;i++)
#define Forr(i,j,k) for(register int i=(j);i>=(int)k;i--) 
#define Rep(i,u) for(register int i=Begin[(u)],v=to[i];i;i=Next[i],v=to[i])
#define N 500010
#define M 1000010
#define pb push_back
using namespace std;
int n,m,s,f[N],to[M],Begin[N],Next[M],e,ans[N];
bool vis[N];
struct node{
    int v,p;
    node(int v=0,int p=0):v(v),p(p){}
};
vector<node>q[N];
inline void add(int x,int y){to[++e]=y,Next[e]=Begin[x],Begin[x]=e;}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void dfs(int u){
    f[u]=u,vis[u]=1;
    Rep(i,u)
        if (!vis[v])
            dfs(v),f[v]=u;
    For(i,0,q[u].size()-1)
        if (vis[q[u][i].v])
            ans[q[u][i].p]=find(q[u][i].v);
}
int main(){
    scanf("%d%d%d",&n,&m,&s);
    For(i,1,n-1){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    For(i,1,m){
        int u,v;
        scanf("%d%d",&u,&v);
        q[u].pb(node(v,i)),q[v].pb(node(u,i));
    }
    dfs(s);
    For(i,1,m)printf("%d\n",ans[i]);
    return 0;
}


二  倍增算法

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define cal_time() printf("Time =%.4lf\n Seconds",1.0*clock()/CLOCKS_PER_SEC)
#define For(i,j,k) for(register int i=(j);i<=(int)k;i++)
#define Forr(i,j,k) for(register int i=(j);i>=(int)k;i--)
#define Rep(i,u) for(register int i=Begin[(u)],v=to[i];i;i=Next[i],v=to[i])
#define N 500010
#define M 1000010
using namespace std;
int to[M],Begin[N],Next[M],e,dep[N],fa[N][21],n,m,s;
inline void add(int x,int y){to[++e]=y,Next[e]=Begin[x],Begin[x]=e;}
void dfs(int u){
    Rep(i,u)
        if(!dep[v])
            dep[v]=dep[u]+1,fa[v][0]=u,dfs(v);
}
inline void st_init(){
    For(j,1,20)
        For(i,1,n)
            fa[i][j]=fa[fa[i][j-1]][j-1];
}
inline int lca(int u,int v){
    if (dep[u]>dep[v])swap(u,v);
    int d=dep[v]-dep[u];
    for(int i=0;(1<<i)<=d;i++)
        if ((1<<i)&d)v=fa[v][i];
    if (u==v)return u;
    Forr(i,20,0)
        if (fa[u][i]!=fa[v][i])
            v=fa[v][i],u=fa[u][i];
    return fa[u][0];
}
int main(){
    scanf("%d%d%d",&n,&m,&s);
    For(i,1,n-1){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }dep[s]=1;
    dfs(s);
    st_init();
    For(i,1,m){
        int u,v;
        scanf("%d%d",&u,&v);
        printf("%d\n",lca(u,v));
    }
    return 0;
}



三   RMQ

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=500010;
int R[N*2],first[N],ver[N*2],to[N*2],Begin[N],Next[N*2],e,tot,f[N*2][21],n,m,s;
bool vis[N];
inline void add(int x,int y){to[++e]=y,Next[e]=Begin[x],Begin[x]=e;}
inline void dfs(int u,int dep){
    vis[u]=1,first[u]=++tot,R[tot]=dep,ver[tot]=u;
    for (int i=Begin[u],v;i;i=Next[i]){
        if(vis[(v=to[i])])continue;
        dfs(v,dep+1);
        R[++tot]=dep,ver[tot]=u;
    }
}
inline void RMQ_init(){
    for (int i=1;i<=tot;i++)f[i][0]=i;
    for (int j=1;(1<<j)<=tot;j++)
        for (int i=1;i+(1<<j)-1<=tot;i++){
            int a=f[i][j-1],b=f[i+(1<<j-1)][j-1];
            if (R[a]<R[b])f[i][j]=a;
            else f[i][j]=b;
        }
}
inline int lca(int u,int v){
    int a=first[u],b=first[v];
    if (a>b)swap(a,b);
    int len=(b-a+1),k=1;
    while((1<<k)<=len)k++;k--;
    if (R[f[a][k]]<R[f[b-(1<<k)+1][k]])return ver[f[a][k]];
    else return ver[f[b-(1<<k)+1][k]];
}
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);
    dfs(s,1);
    RMQ_init();
    for (int i=1,u,v;i<=m;i++)scanf("%d%d",&u,&v),printf("%d\n",lca(u,v));
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值