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

来源:互联网 发布:麦田的守望者 知乎 编辑:程序博客网 时间:2024/05/19 22:02

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


在线算法模板:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片#include <cstdio>  #include <iostream>  #include <cstring>  #include <algorithm>    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<<j)<=n;j++)              for(int i=1;i+(1<<j)-1<=n;i++)                  d[i][j] = A[d[i][j-1]] < A[d[i+(1<<(j-1))][j-1]]? d[i][j-1]:d[i+(1<<(j-1))][j-1];      }      int rmqIndex(int L,int R,int A[])      {          int k=0;          while ((1<<(k+1))<=R-L+1) k++;          return A[d[L][k]]<A[d[R-(1<<k)+1][k]]? d[L][k]:d[R-(1<<k)+1][k];      }      //---------------------      int E[maxn*2],R[maxn],D[maxn*2],mn;      void dfs(int u,int p,int d){          E[++mn]=u;          D[mn]=d;          R[u]=mn;          for (int i=head[u];i!=-1;i=edges[i].next){              int v=edges[i].to;              if (v==p) continue;              dfs(v,u,d+1);              E[++mn]=u;              D[mn]=d;          }      }      void LCA_init(){          mn=0;          memset(R,0,sizeof(R));          dfs(1,-1,1);          makeRmqIndex(D,mn);          getd(1,-1,0);      }      int LCA(int u,int v){          if (R[u]>=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 <stdio.h>#include <string.h>#include <iostream>#include <algorithm>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)];        }    }}


0 0