LCA算法模板(离线算法,在线算法)

来源:互联网 发布:阿里云cdn签名 编辑:程序博客网 时间:2024/06/06 11:46

这两个模板都是针对的同一棵树;

如果两个点存在不在同一棵树上的情况,我们可以加个并查集来解决,

即两个点不在一棵树上,他们就不能够相互到达,如果在同一棵树上,就求他们的lca

/**hdu 2586  LCA模板题(离线算法)题目大意:给一个无根树,有q个询问,每个询问两个点,问两点的距离。解题思路:求出  lca = LCA(X,Y) , 然后  dir[x] + dir[y] - 2 * dir[lca],          dir[u]表示点u到树根的距离*/#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;int m,n;int father[maxn],vis[maxn],ance[maxn],dir[maxn];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;    ance[u]=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=ance[Find(v)];        }    }}int main(){   int T;   scanf("%d",&T);   while(T--)   {       init();       scanf("%d%d",&n,&m);       for(int i=1;i<n;i++)       {           int u,v,w;           scanf("%d%d%d",&u,&v,&w);           addedge(u,v,w);           addedge(v,u,w);       }       for(int i=0;i<m;i++)       {           int u,v;           scanf("%d%d",&u,&v);           addedge1(u,v);           addedge1(v,u);       }       dir[1]=0;       tarjan(1);       for(int i=0;i<m;i++)       {           int s=i*2,u=edge1[s].u,v=edge1[s].v,lca=edge1[s].lca;           printf("%d\n",dir[u]+dir[v]-2*dir[lca]);       }   }   return 0;}


在线算法 RMQ/**hdu 2586  LCA (在线算法)解题思路:转为RMQ在线算法求解,也是模板题*/#include <stdio.h>#include <string.h>#include <algorithm>#include <iostream>#include <math.h>using namespace std;const int maxn=40010;const int maxm=25;int _pow[maxm],m,n;int head[maxn],ip;int ver[maxn*2],R[maxn*2],first[maxn],dir[maxn],dp[maxn*2][maxm],tot;bool vis[maxn];void init(){    memset(vis,false,sizeof(vis));    memset(head,-1,sizeof(head));    ip=0;}struct note{    int v,w,next;}edge[maxn*2];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 dfs(int u,int dep){    vis[u]=true;    ver[++tot]=u,first[u]=tot,R[tot]=dep;    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;            dfs(v,dep+1);            ver[++tot]=u,R[tot]=dep;        }    }}void ST(int len){    int k=(int)log((double)len)/(log(2.0));    for(int i=1;i<=len;i++)    {        dp[i][0]=i;    }    for(int j=1;j<=k;j++)    {        for(int i=1;i+_pow[j]-1<=len;i++)        {            int a=dp[i][j-1],b=dp[i+_pow[j-1]][j-1];            if(R[a]<R[b])                dp[i][j]=a;            else                dp[i][j]=b;        }    }}int RMQ(int x,int y){    int k=(int)log((double)(y-x+1)/log(2.0));    int a=dp[x][k],b=dp[y-_pow[k]+1][k];    if(R[a]<R[b])        return a;    else        return b;}int LCA(int u,int v){    int x=first[u],y=first[v];    if(x>y)swap(x,y);    int res=RMQ(x,y);    return ver[res];}int main(){    for(int i=0;i<maxn;i++)_pow[i]=(1<<i);    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&m);        init();        for(int i=1;i<n;i++)        {            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            addedge(u,v,w);            addedge(v,u,w);        }        tot=0,dir[1]=0;        dfs(1,1);        ST(2*n-1);        while(m--)        {            int u,v;            scanf("%d%d",&u,&v);            int lca=LCA(u,v);            printf("%d\n",dir[u]+dir[v]-2*dir[lca]);        }    }    return 0;} 

模板来自 http://blog.csdn.net/lvshubao1314/article/details/44001481,感谢大佬