LCA最近公共祖先 在线算法和离线算法 模板

原理讲解:http://dongxicheng.org/structure/lca-rmq/


在线算法模板:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
#include   
#include   
#include   
#include   
  
using namespace std;  
const int INF=0x3f3f3f;  
const int maxn=111111;  
const int maxm=111111;  
int n,m;  
  
struct EDGENODE{  
    int to;  
    int w;  
    int next;  
};  
struct SGRAPH{  
    int head[maxn];  
    EDGENODE edges[maxm];  
    int edge;  
    void init(){  
        memset(head,-1,sizeof(head));  
        edge=0;  
    }  
    void addedge(int u,int v,int c){  
        edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;  
    }  
    //------------  
    int d[maxn][20];  
    //元素从1编号到n  
    void makeRmqIndex(int A[],int n){  
        for(int i=1;i<=n;i++) d[i][0]=i;  
        for(int j=1;(1<=R[v]) return E[rmqIndex(R[v],R[u],D)];  
        else return E[rmqIndex(R[u],R[v],D)];  
  
    }  
    //--------------------  
    int deep[maxn];  
    void getd(int u,int p,int w){  
        deep[u]=w;  
        for (int i=head[u];i!=-1;i=edges[i].next){  
            int v=edges[i].to;  
            if (v==p) continue;  
            getd(v,u,w+edges[i].w);  
        }  
    }  
    int getDis(int u,int v){  
        int lca=LCA(u,v);  
        return deep[u]+deep[v]-deep[lca]*2;  
    }  
    int done(int x,int y,int z){  
        int ans=INF,res=0;  
        int lca1,lca2;  
  
        lca1=LCA(x,y);  
        res=deep[x]+deep[y]-deep[lca1]*2;  
        lca2=LCA(lca1,z);  
        res+=deep[lca1]+deep[z]-deep[lca2]*2;  
        ans=min(ans,res);  
  
        lca1=LCA(x,z);  
        res=deep[x]+deep[z]-deep[lca1]*2;  
        lca2=LCA(lca1,y);  
        res+=deep[lca1]+deep[y]-deep[lca2]*2;  
        ans=min(ans,res);  
  
        lca1=LCA(y,z);  
        res=deep[y]+deep[z]-deep[lca1]*2;  
        lca2=LCA(lca1,x);  
        res+=deep[lca1]+deep[x]-deep[lca2]*2;  
        ans=min(ans,res);  
  
        return ans;  
    }  
}solver;  


离线求解:

/**
LCA(离线算法)
主函数除建边外还应调用
init();
dir[1]=0;
tarjan(1);
*/
#include 
#include 
#include 
#include 
using namespace std;
const int maxn=40010;

struct note
{
    int u,v,w,lca,next;
}edge[maxn*2],edge1[805];

int head[maxn],ip,head1[maxn],ip1;///需要建两次边。1,该树的边2,需要查询的两点
int m,n;
int father[maxn],vis[maxn],dir[maxn];
///依次表示u点的祖先、标记是否访问过,到根节点的距离

void init()
{
    memset(vis,0,sizeof(vis));
    memset(dir,0,sizeof(dir));
    memset(head,-1,sizeof(head));
    memset(head1,-1,sizeof(head1));
    ip=ip1=0;
}

void addedge(int u,int v,int w)
{
    edge[ip].v=v,edge[ip].w=w,edge[ip].next=head[u],head[u]=ip++;
}

void addedge1(int u,int v)
{
    edge1[ip1].u=u,edge1[ip1].v=v,edge1[ip1].lca=-1,edge1[ip1].next=head1[u],head1[u]=ip1++;
}

int  Find(int x)
{
    if(father[x]==x)
        return x;
    return father[x]=Find(father[x]);
}

void Union(int x,int y)
{
    x=Find(x);
    y=Find(y);
    if(x!=y)
        father[y]=x;
}

void tarjan(int u)
{
    vis[u]=1;
    father[u]=u;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        int w=edge[i].w;
        if(!vis[v])
        {
           dir[v]=dir[u]+w;
           tarjan(v);
           Union(u,v);
        }
    }
    for(int i=head1[u];i!=-1;i=edge1[i].next)
    {
        int v=edge1[i].v;
        if(vis[v])
        {
            edge1[i].lca=edge1[i^1].lca=father[Find(v)];
        }
    }
}



你可能感兴趣的:(图论,LCA,模板)