LCA向RMQ轉化

來源:互聯網
上載者:User

1,最近公用祖先(LCA):
對於有根樹T的兩個結點u、v,最近公用祖先LCA(T,u,v)表示一個結點x,滿足x是u、v的祖先且x的深度儘可能大。
2,LCA問題向RMQ問題的轉化方法:(RMQ返回最值的下標)
對樹進行深度優先遍曆,每當“進入”或回溯到某個結點時,將這個結點的深度存入數組dfsNum最後一位。同時記錄結點i在數組中第一次出現的位置(事實上就是進入結點i時記錄的位置),記做first[i]。如果結點dfsNum[i]的深度記做depth[i],易見,這時求LCA(u,v),就等價於求 E[RMQ(depth,first[u],first[v])],(first[u]<first[v])。
例如:

(深度遍曆)difNum[i]為:1,2,1,3,4,3,5,3,1
first[i]為:0,1,3,4,6
(個點對應的深度)depth[i]為:0,1,0,1,2,1,2,1,0

於是有:
LCA(4,2) = difNum[RMQ(D,first[2],first[4])] = difNum[RMQ(D,1,6)] = difNum[2] = 1

轉化後得到的數列長度為樹的結點數*2-1(每經過一條邊,都會記錄端點,有N-1條邊,所以會回溯N-1次。且每個頂點都會被添加一次,所以長度為2N-1)

3,執行個體代碼:

#include<iostream>  #include<vector>  #include<cmath>  #include<algorithm>  using namespace std;    const int maxn=20010;    struct node //可以添加額外的資訊  {      int v;//孩子結點  };    //注意vector在樹問題中的使用  vector<node> tree[maxn];    int dfsnum[maxn]; //記錄遍曆的節點  int depth[maxn]; //記錄節點對應的深度  int first[maxn]; //記錄結點第一次訪問到時的下標  int top; //記錄總的步伐數    void dfs(int m,int f,int dep) //當前節點編號,父節點編號,深度  {      dfsnum[top]=m;      depth[top]=dep;      first[m]=top;      top++;      for(unsigned i=0;i<tree[m].size();i++)      {          if(tree[m][i].v==f)              continue;          dfs(tree[m][i].v,m,dep+1);          dfsnum[top]=m; //注:每條邊回溯一次,所以top的值=n+n-1          depth[top]=dep;          top++;      }  }    int dp[maxn][18];  void makeRmqIndex(int n,int b[]) //返回最小值對應的下標  {      int i,j;      for(i=0;i<n;i++)          dp[i][0]=i;      for(j=1;(1<<j)<=n;j++)          for(i=0;i+(1<<j)-1<n;i++)              dp[i][j]=b[dp[i][j-1]] < b[dp[i+(1<<(j-1))][j-1]]? dp[i][j-1]:dp[i+(1<<(j-1))][j-1];  }  int rmqIndex(int s,int v,int b[])  {      int k=(int)(log((v-s+1)*1.0)/log(2.0));      return b[dp[s][k]]<b[dp[v-(1<<k)+1][k]]? dp[s][k]:dp[v-(1<<k)+1][k];  }   int lca(int x,int y)  {      return dfsnum[rmqIndex(first[x],first[y],depth)];  }    int main()  {      int n=5;//頂點數      top=0;      //分別存放每條邊的端點      int x[]={1,1,3,3};      int y[]={2,3,4,5};      node temp;      for(int i=0;i<n-1;i++) //n-1條邊      {          temp.v=y[i];          tree[x[i]].push_back(temp);          temp.v=x[i];          tree[y[i]].push_back(temp);      }      dfs(1,-1,0); //根節點為1      cout<<"總數:"<<top<<endl;      makeRmqIndex(top,depth);      cout<<"dfsnum:";      for(int i=0;i<top;i++)      {          cout<<dfsnum[i]<<" ";      }      cout<<endl;      cout<<"depth:";      for(int i=0;i<top;i++)      {          cout<<depth[i]<<" ";      }    cout<<endl;      cout<<"first:";      for(int i=1;i<=n;i++)      {          cout<<first[i]<<" ";      }      cout<<endl;      cout<<"lca(4,5):"<<lca(4,5)<<endl;      cout<<"lca(2,4):"<<lca(2,4)<<endl;      cout<<"lca(1,4):"<<lca(1,4)<<endl;      return 0;  }  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.