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:
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