LCA&RMQ

LCA问题
 给定一棵有根树T,对于任意两个节点u,v,求出LCA(T,u,v)

 LCA的tarjan算法 (离线算法)
 //初始所有节点color为WHITE
 void LCA(u)
 {
  MAKE_SET(u);
  ancester[FIND_SET(u)]=u;
  for(u的每个儿子v)
  {
   LCA(v);
   UNION(u,v);
   ancester[FIND_SET(u)]=u;
  }
  color[u]=BLACK
  for(Q(u)中的所有元素)
  {
   if(color[v]==BLACK)
   printf("LCA(%d,%d)=%d\n",u,v,ancester[FIND_SET(v)]);
  }
 }


 MAKE_SET(u)表示建立一个只有u的集合,且u为集合的代表元
 FIND_SET(u)表示找出集合的代表元
 UNION(u,v) 表示合并u,v所在的集合


RMQ问题
 给定一个长度为n的数组n,回答询问RMQ(A,i,j),即A[i..j]中元素最小的数的下标


 将LCA问题转化为RMQ问题

  1.DFS遍历树,记录遍历到的节点E[1..2n-1],
    并用R[i]表示E数组中第一个值为i的元素的下标
  2.对于任意 R[u]<R[v] ,dfs中第一次访问u到第一次访问v的路径是E[R[u]..R[v]]
    并且其中深度最小的节点一定是u,v的LCA
  3.令数组L[i]表示节点E[i]的深度,那么当R[u]<R[v]时,LCA(T,u,v)=RMQ(L,R[u],R[v]);
 转换后的RMQ问题比较特殊,相邻两个元素的相差1或-1,这样的问题成为+_1-RMQ


 一般RMQ的Spare Table(ST) 算法
  d[i,j]表示从i开始长度为2^j的区间的RMQ,
  则有递推公式 d[i,j]=min(d[i][j-1],d[i+2^(j-1),j-1]),即用两个相邻的长度为2^(j-1)
  的区间来分形长度为2^j的区间    预处理时间复杂度为O(nlogn)

  询问时 取k=log2(j-i+1)令A为从i开始的长度为2^k的块的RMQ
          令B为到j结束的长度为2^k的块的RMQ
   则RMQ(i,j)=min(A,B),
   即 k=log2(j-i+1),RMQ[i,j]=min(d[i,k],d[j-2^k+1,k])

 +_1-RMQ的O(n)-O(1)算法
  ………………………………


未完待续…………



////////
写了个lca的代码
不知道对不对
#include<stdio.h>
#include<string.h>
#include<math.h>
#define maxn 505
#define black 1
#define white 0
int father[maxn],ancester[maxn];
int color[maxn];
struct node
{
    int v,next;
} edge[maxn*maxn];
int p[maxn];
int n,e,m;
int root;
void add(int u,int v)
{
    edge[e].v=v;
    edge[e].next=p[u];
    p[u]=e++;
}
int find(int u)
{
    if (u==father[u]) return u;
    else 
 {
  father[u]=find(father[u]);
 }//路径压缩
    return father[u];
}
void union1(int u,int v)
{
    int tmp,tmp1;
    tmp=find(u);
    tmp1=find(v);
    father[tmp1]=tmp;
}
void lca(int u)
{
    int i,v,v1;
    father[u]=u;
    ancester[find(u)]=u;
    for(i=p[u]; i!=-1; i=edge[i].next)
    {
        v=edge[i].v;
        lca(v);
        union1(u,v);
        ancester[find(u)]=u;
    }
    /*for(i=p1[u]; i!=-1; i=edge1[i].next)
    {
        v1=edge1[i].v;
        if (color[v1]==black)
            printf("LCA(%d,%d)=%d\n",u,v1,ancester[find(v)]);
    }*/
    color[u]=black;
 for(i=1;i<=n;i++)
  if(i!=u)
 {
  if (color[i]==black)
  {
   printf("LCA(%d,%d)=%d\n",u,i,ancester[find(i)]);
  }
 }
}
int main()
{
    int a,b,i;
    scanf("%d%d",&n,&m);
    scanf("%d",&root);
    memset(p,-1,sizeof(p));
    e=0;
    for(i=1; i<=m; i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
    }
    for(i=1; i<=n; i++) father[i]=i;
    memset(color,white,sizeof(color));
    lca(1);
    return 0;
}

posted on 2012-04-30 11:39 jh818012 阅读(134) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿

文章档案(85)

搜索

最新评论