RMQ求LCA【ST】算法

RMQ求LCA其實非常簡單的啦

我們需要理解兩個基本的工具:

1.歐拉序列;

2.線段樹,二叉搜索樹或者其它基本區間尋求最值的方法;

所以說LCA和區間有什麼關係?

舉個栗子:

我們將歐拉序列E打出:

【1,2,4,2,5,2,1,3,6,3,1】(先自己想想怎麼實現)

在打印序列的同時記錄下每個節點第一次出現的位置R

【1,2,8,3,5,9】

另外別忘了給歐拉序列標深度L

【1,2,3,2,3,2,1,2,3,2,1】

接下來區間最值的作用就發揮了作用了:

比如我們要找4和5LCA,我們只需要在R數組中找到【3,5】中深度最小的節點就行了;

而對應的區間可以通過R數組來確定;

接下來是moban(蒟蒻只能用領接鏈表建):

首先是歐拉序列的打印:

 
void dfs(int u,int dep)
{ tot++;
   R[u]=tot;//這裏是第一次出現的位置;
   L[tot]=dep;
   E[tot]=u;
   vis[u]=true;
for(int i=head[u];i!=0;i=nex[i])
{int v=to[i];
    if(!vis[v]){    
    dis[v]=dis[u]+w[i];
    dfs(v,dep+1);
    E[++tot]=u;//別忘了回到u節點記錄;
    L[tot]=dep;}
}
}

接下來是ST對序列進行處理(我們記錄的不是最小深度,而是最小深度對應的節點

不明白ST的可以看我的另一篇博客:https://blog.csdn.net/Wyt_code/article/details/83832104

void found()//STmoban不多說;
{ for(int i=1;i<=tot;i++)
    f[i][0]=i;
  int n=(int)(log(tot)/log(2));
   for(int j=1;j<=n;j++)
       for(int i=1;i<=tot;i++)
           if(i+(1<<j)-1<=tot){
               int a=f[i][j-1];int b=f[i+(1<<j-1)][j-1];
               if(L[a]<L[b]) f[i][j]=a;//注意是記錄下標以便確定節點;
                 else f[i][j]=b;
                 }
             }

接下來是RMQ和LCA的查詢(爲了便於理解我分成兩個板塊) 

int RMQ(int l,int r)
{int j=(int)(log(r-l+1)/log(2));
int a=f[l][j];int b=f[r-(1<<j)+1][j];
return L[a]<L[b]?a:b;//還是返回數組對應下標;
}
 
int LCA(int l,int r)
{ l=R[l];r=R[r];//確定區間;
    if(l>r) swap(l,r);
    return E[RMQ(l,r)];//讀求下標對應節點;
}   

emmmm好像就這些了 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章