July 2019 Training (LU)

LCA doubling method

Template: Luogo  P3379 [template] recent common ancestor (LCA)

Today ran a little time talking about God, and now humbly to cram (dish)

LCA refers to the most recent common ancestor (Least Common Ancestors).

The simplest algorithm is undoubtedly going up from two points one by one, appearing first two points are traversed point is the two points LCA.

But time is very long.

So only use doubling, doubling role is to rise two points to reduce the complexity required .

Is a general process: deep two different points in the same layer jump, then jump deep [lca-1] that layer, and then jump up the layer is lca.

 

The method is to accelerate jump jump up each i-th layer of the layers 2, the number of layers is to be converted into binary numbers, so that the time complexity becomes log2 (n) a.

 

After two arrays to F [i] [j] ( up after 2 ^ j arrived from layer i ) and Deep [i] ( the depth of the tree in point i ).

deep [i] obtained with a dfs.

f [i] [j] by a recursive, f [i] [j] = f [f [i] [j-1]] [j-1]. Initialization f [i] [0] may be determined at the time of traversing the entire tree.

Then, at the same time two approaching up again. i begins the enumeration of the most significant bit, respectively, assuming two points x, y, it can jump up is determined as the formula:

if (f[x][i]!=f[y][i])
{
       x=f[x][i];
       y=f[y][i];   
}

 

If the two is 2 ^ i jump up less than the same layer after a point to then jump up. why is it like this? Because if a jump up 2 ^ i layer, even to the same point, it is not necessarily two points LCA.

In doing so, it will eventually reach the layer below the LCA. We then jump up again two layer. LCA determined.

Then this makes me very puzzled question arises:

Why will eventually reach the layer below the LCA?

We start from the assumption that a, b point, jump up 2 ^ j layer, jump to the same point. do not jump. Jump up 2 (j-1) ^ layer, is not the same point jump, jump up, respectively, to A ', B'. Obviously, this situation will certainly exist. Then, from A ', B' and then further on that decision not to jump to the original point of the jump, jump obviously 2 ^ (j-1) layer. Well, that point may be the LCA, there may not be, right? Therefore, from A ', B' jump up LCA desired number of layers is ≤2 ^ (j-1) a. In other words, A ', B' to X number of layers into a binary number a j-2 bits (leading zeros may be, which is also the same jump points may place). By this time, just enumerate j-2 bits. So, leading zeros are not reduced, then so cut down, you find that the difference between the number of layers will eventually become zero, and you will eventually reach the layer X.

Probably your uncle (father's brother) is not your ancestors here to find ancestors must be lineal.

Why the difference between the number of layers will eventually become X 0?

First we prove, leading zeros are not subtracted. The difference between the number of layers is assumed that the X layer is x ', and you are ready to jump up y layer. Due to the number of layers is the LCA X + 1, and LCA-up point it will not jump, right? (Instead, if the LCA down point, that is, the number of layers <= X, that is, y <x '+ 1, it will jump up) so if y> = x' + 1, then it will not up jump.

Obviously, when x 'of the bit 0, and belong to a leading zero, then only prove x' + 1 <= y. And this is very easy to prove that (assuming 10000 y, and x 'satisfies the condition of maximum 01,111) . So I guarantee, leading zeros are not subtracted.

Then we prove, once to enumerate x 'first digit is 1, this one will definitely be subtracted. In the same manner, assuming that y is 10000, and x 'satisfies the condition of the minimum of 10,000, the y <x' + 1.

Two together, leading zeros do not subtract, to enumerate a one subtracted, the final layers of this difference becomes 0. proof.

Code:

#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<cmath>
#define  maxn 500010
#include<queue>
using namespace std;

int f[maxn][21],head[maxn],deep[maxn],cnt,n,m,rt;
struct edge
{
    int v,next;
}e[maxn<<1];

void add(int u,int v)
{
    e[++cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}

void dfs(int x,int fa)
{
    f[x][0]=fa;
    deep[x]=deep[fa]+1;
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].v;
        if(v==fa) continue;
        dfs(v,x);
    }
}

void Init()
{
    for(int j=1;(1<<j)<=n;++j)
    {
        for(int i=1;i<=n;++i)
        {
            if(deep[i]>=(1<<j))
            {
                f[i][j]=f[f[i][j-1]][j-1];
            }
        }
    }
}

int query(int x,int y)
{
    if(deep[x]<deep[y]) swap(x,y);
    int d=deep[x]-deep[y];
    for(int j=20;j>=0;--j) if(d&(1<<j)) x=f[x][j];
    if(x==y) return x;
    for(int j=20;j>=0;--j)
    {
        if(f[x][j]!=f[y][j])
        {
            x=f[x][j];
            y=f[y][j];
        }
    }
    return f[x][0];
}

int main()
{
    int u,v;
    scanf("%d%d%d",&n,&m,&rt);
    
    for(int i=1;i<n;++i)
    {
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    
    dfs(rt,0);
    Init();
    while(m--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",query(x,y));
    }
    return 0;
}

2019-07-3122:54:32

Guess you like

Origin www.cnblogs.com/plzplz/p/11279752.html