Tuesday, 12 April 2016

***LCA USING BINARY RAIS TREE tutorial

Another easy solution in <O(N logN, O(logN)>
If we need a faster solution for this problem we could use dynamic programming. First, let’s compute a table P[1,N][1,logN] where P[i][j] is the 2j-th ancestor of i. For computing this value we may use the following recursion:
The preprocessing function should look like this:
  void process3(int N, int T[MAXN], int P[MAXN][LOGMAXN])
  {
      int i, j;
   
  //we initialize every element in P with -1
      for (i = 0; i < N; i++)
          for (j = 0; 1 << j < N; j++)
              P[i][j] = -1;
   
  //the first ancestor of every node i is T[i]
      for (i = 0; i < N; i++)
          P[i][0] = T[i];
   
  //bottom up dynamic programing
      for (j = 1; 1 << j < N; j++)
         for (i = 0; i < N; i++)
             if (P[i][j - 1] != -1)
                 P[i][j] = P[P[i][j - 1]][j - 1];
  }
  
This takes O(N logN) time and space. Now let’s see how we can make queries. Let L[i] be the level of node i in the tree. We must observe that if p and q are on the same level in the tree we can compute LCA(p, q) using a meta-binary search. So, for every power j of 2 (between log(L[p]) and 0, in descending order), if P[p][j] != P[q][j] then we know that LCA(p, q) is on a higher level and we will continue searching for LCA(p = P[p][j], q = P[q][j]). At the end, both p and q will have the same father, so return T[p]. Let’s see what happens if L[p] != L[q]. Assume, without loss of generality, that L[p] < L[q]. We can use the same meta-binary search  for finding the ancestor of p situated on the same level with q, and then we can compute the LCA  as described below. Here is how the query function should look:
  int query(int N, int P[MAXN][LOGMAXN], int T[MAXN], 
  int L[MAXN], int p, int q)
  {
      int tmp, log, i;
   
  //if p is situated on a higher level than q then we swap them
      if (L[p] < L[q])
          tmp = p, p = q, q = tmp;
  
  //we compute the value of [log(L[p)]
      for (log = 1; 1 << log <= L[p]; log++);
      log--;
   
  //we find the ancestor of node p situated on the same level
  //with q using the values in P
      for (i = log; i >= 0; i--)
          if (L[p] - (1 << i) >= L[q])
              p = P[p][i];
   
      if (p == q)
          return p;
   
  //we compute LCA(p, q) using the values in P
      for (i = log; i >= 0; i--)
          if (P[p][i] != -1 && P[p][i] != P[q][i])
              p = P[p][i], q = P[q][i];
   
      return T[p];
  }
Now, we can see that this function makes at most 2 * log(H) operations, where H is the height of the tree. In the worst case H = N, so the overall complexity of this algorithm is <O(N logN), O(logN)>. This solution is easy to code too, and it’s faster than the previous one

-----------------------------------CODE----------------------------------------------------------------------
// tree is treated as 1 based 
// level is also 1 based 

#include<bits/stdc++.h>
using namespace std;
typedef long long int lli;
list<int>li[1010];
lli dp[1010][30];
int lev[1010];
int dfs(int start,int par,int le)
{

  lev[start]=le;
  list<int>:: iterator it;
  for(it=li[start].begin();it!=li[start].end();it++)
   {
     if(*it!=par)
      {
        dp[*it][0]=start;
        lev[*it]=le+1;
        dfs(*it,start,le+1);
   }
   }
}


int binary_rais(int a,int b)// return lca of a,b
 {
  
    //  always we conseider that lev a> lev b so swap else
   if(lev[a]<lev[b]) swap(a,b);
   
   int lg;
   
   /// maximum jump that can be alloweable to make both a and 
   // b at same level  will be the depth of the node a 
   for(lg=1;(1<<lg)<=lev[a];lg++);
   
   // 
   lg--;
   
   // this will make both at same level
   //  we can write any number as the power of 2 
   //  so by binary raise we can reach to any node 
     for(int i=lg;i>=0;i--)
      {
        if(lev[a]-(1<<i)>=lev[b])
         {
            a=dp[a][i];//   moving a upward
          }
      }
    
    //  now a and b are at same level 
    
    
      //now we always try to  to shift a and be at a point just below the lca
      //  but if both a and b are in the same line than while shifing leven we reach 
      //  both a and become same 
    
   if(a==b) return a;
   
   else
   {
    for(int i=lg;i>=0;i--)
    {
     if(dp[a][i]!=-1 && dp[a][i]!=dp[b][i])//  moving botha and b up 
      {
        a=dp[a][i];
        b=dp[b][i];
      }
    }
    //  since we atmax shift a and b 
    //  just below there lca 
    //  lca will be the parent of a or parent of b
    
    return dp[a][0];
   }
 }


int main()
{

 int t;
  cin>>t;
  int cas=1;
  while(t--)
  {
    cout<<"Case "<<cas++<<":"<<endl;
    for(int i=0;i<1010;i++)li[i].clear();
 int n;
 cin>>n;
 int m ;
  cin>>m;// edge 
  
 for(int i=1;i<=m;i++)
 {
   int a,b;
    cin>>a>>b;
    li[a].push_back(b);
    li[b].push_back(a);
}

 memset(dp,-1,sizeof dp);
 // we are consedering 1 as the root of all nodes 
 // so its parent is non so its pow(2,0) the parent is 0;

 dp[1][0]=0;
 dfs(1,-1,1);

    int max_h=20;//  or lon(n)
    //  maximum height 
    for(int i=1;i<=max_h;i++)
     {
       for(int j=1;j<=n;j++)
        {
            if(dp[j][i-1]!=-1)
       dp[j][i]=dp[dp[j][i-1]][i-1];//
     }
  }
  
  int q;
  cin>>q;
  while(q--)
   {
     int a,b;
      cin>>a>>b;
      cout<< binary_rais(a,b)<<endl;
   }
 }

}

No comments:

Post a Comment