最近公共祖先LCA模板(Tarjan/RMQ)

Description


給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。
洛谷P3379 【模板】最近公共祖先(LCA)

Solution


每次想數組名字都想的異常艱難,於是(因果關係?)這裏存一下模板

離線算法 Tarjan

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
int father[500005],visited[500005];
int n,m,s; 
int head[500005],cnt=0,head1[500005],cnt1=0;
struct Node{
    int next,to;
}edges[1000005];
void addedge(int u,int v)
{
    edges[cnt].next=head[u];
    head[u]=cnt;
    edges[cnt++].to=v;
}
struct Node1{
    int next,to,lca;
}edges1[1000005];
void addedge1(int u,int v)
{
    edges1[cnt1].next=head1[u];
    head1[u]=cnt1;
    edges1[cnt1++].to=v;
}
int getfather(int x)
{
    if(father[x]==x)return x;
    father[x]=getfather(father[x]);
    return father[x];
}
void _union(int x,int y)
{
    int fx=getfather(x),fy=getfather(y);
    if(fx!=fy)father[fx]=fy;
}
void tarjan(int u)
{
    visited[u]=1;
    father[u]=u;
    for(int i=head[u];~i;i=edges[i].next)
    {
        int t=edges[i].to;
        if(!visited[t])
        {
            tarjan(t);
            _union(t,u);
        }
    }
    for(int i=head1[u];~i;i=edges1[i].next)
    {
        int t=edges1[i].to;
        if(visited[t])
        {
            edges1[i].lca=edges1[i^1].lca=getfather(t);
        }
    }
}
int main()
{
    memset(head,-1,sizeof(head));
    memset(head1,-1,sizeof(head1));
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }
    for(int i=1;i<=m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        addedge1(a,b);
        addedge1(b,a);
    }
    tarjan(s);
    for(int i=0;i<2*m;i+=2)
    {
        printf("%d\n",edges1[i].lca);
    }
    return 0;
} 

在線算法 RMQ

這個感覺容易爆內存,至少在交洛谷模板題的時候是qwq

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#define Min(a,b) (a<b?a:b)
using namespace std;
int n,m,s;
int head[500005],cnt=0,first[500005],dep[1000005];
int vertex[1000005],rmq[1000005][20],dfs_clock=0;
bool visited[500005];
struct Node{
    int next,to;
}Edges[1000005];
void add(int u,int v)
{
    Edges[cnt].next=head[u];
    head[u]=cnt;
    Edges[cnt].to=v;
    cnt++;
}
void dfs(int u,int depth)
{
    visited[u]=1;
    ++dfs_clock;first[u]=dfs_clock;
    vertex[dfs_clock]=u;
    dep[dfs_clock]=depth;
    for(int i=head[u];~i;i=Edges[i].next)
    {
        int t=Edges[i].to;
        if(!visited[t])
        {
            dfs(t,depth+1);
            vertex[++dfs_clock]=u;
            dep[dfs_clock]=depth;
        }
    }
}
void RMQinit()
{
    for(int i=1;i<=dfs_clock;i++)
    rmq[i][0]=i;
    for(int j=1;(1<<j)<=dfs_clock;j++)
    for(int i=1;i+(1<<j)-1<=dfs_clock;i++)
    {
        if(dep[rmq[i][j-1]]<dep[rmq[i+(1<<(j-1))][j-1]])
        rmq[i][j]=rmq[i][j-1];
        else rmq[i][j]=rmq[i+(1<<(j-1))][j-1];
    }
}
int RMQ(int x,int y)
{
    int l=first[x],r=first[y];
    if(l>r)swap(l,r);
    int k=0;
    while((1<<(k+1))<=r-l+1)k++;
    int a=rmq[l][k],b=rmq[r-(1<<k)+1][k];
    if(dep[a]<dep[b])return a;
    return b;
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d%d",&n,&m,&s);
    int x,y;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(s,1);
    RMQinit();
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        printf("%d\n",vertex[RMQ(x,y)]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章