Ways to find LCA (the most recent common ancestor)

Source: Internet
Author: User
Tags cmath

In fact, I learned the method of LCA earlier, but there was no habit of summarizing it at that time. Violent Jump up

First jump the x,y to the same level, and then jump up at the same time until it becomes the same point, obviously the point is their LCA.
Time complexity is the depth of the tree, the tree into a chain, GG.

#include <cstdio> #include <algorithm> #define FO (i, x, y) for (int i = x; i <= y; i + +) using namespace Std;
const int MAXN = 100005;
int n, x, y;
int FINAL[MAXN], tot; struct Edge {int next, to;}

E[MAXN * 2];

int BZ[MAXN], DEP[MAXN], FA[MAXN];
    void link (int x, int y) {e[++ tot].next = final[x], e[tot].to = y, final[x] = tot;
e[++ Tot].next = Final[y], e[tot].to = x, final[y] = tot;
    } void DG (int x) {bz[x] = 1;
        for (int k = final[x]; k; k = e[k].next) {int y = e[k].to; if (bz[y]) continue;
        Dep[y] = dep[x] + 1;
        Fa[y] = x;
    DG (y);
    } void Init () {scanf ("%d", &n);
        Fo (i, 1, n-1) {scanf ("%d%d", &x, &y);
    Link (x, y);
    } int Lca (int x, int y) {if (Dep[x] < dep[y]) swap (x, y);
    while (Dep[y] > dep[x]) y = fa[y];
    while (x!= y) x = fa[x], y = fa[y];
return x;

void Build () {dep[1] = 1; DG (1);}
    int main () {Init ();

    Build (); scanf ("%d%D ", &x, &y);
printf ("%d", Lca (x, y));
 }
Double Jump Method

Maintain each point up to jump 2^j layer after which point, this is a multiplier table, the process and RMQ similar (see superscript).
Suppose to have X,y (Dep[x] < dep[y])
Jump y to x first.
Then start the second approximation, and keep approaching to the point below the LCA, and the next level is the LCA.

#include <cstdio> #include <algorithm> #define FO (i, x, y) for (int i = x; i <= y; i + +) #define FD (i, x, y) F

or (int i = x; i >= y; i-) using namespace Std;
const int MAXN = 100005, maxc = 16;
int n, x, y;
int FINAL[MAXN], tot; struct Edge {int next, to;}

E[MAXN * 2];
int BZ[MAXN], DEP[MAXN], FA[MAXN];

int FJ[MAXC + 1][MAXN];
    void link (int x, int y) {e[++ tot].next = final[x], e[tot].to = y, final[x] = tot;
e[++ Tot].next = Final[y], e[tot].to = x, final[y] = tot;
    } void DG (int x) {bz[x] = 1;
        for (int k = final[x]; k; k = e[k].next) {int y = e[k].to; if (bz[y]) continue;
        Dep[y] = dep[x] + 1;
        Fa[y] = x;
    DG (y);
    } void Init () {scanf ("%d", &n);
        Fo (i, 1, n-1) {scanf ("%d%d", &x, &y);
    Link (x, y);
    } int Lca (int x, int y) {if (Dep[x] < dep[y]) swap (x, y);
    FD (i, MAXC, 0) if (Dep[fj[i][y]] >= dep[x]) y = fj[i][y]; FD (i, MAXC, 0) if (fj[i][x]!= Fj[i][y]) x = fj[i][x], y = fj[i][y]; return x = = y?
X:FA[X];
    void Build () {dep[1] = 1; DG (1);
    Fo (i, 1, n) fj[0][i] = Fa[i];
Fo (j, 1, MAXC) fo (i, 1, n) fj[j][i] = fj[j-1][fj[j-1][i]];
    int main () {Init ();

    Build ();
    scanf ("%d%d", &x, &y);
printf ("%d", Lca (x, y));
 }
Oura +RMQ to seek LCA

Euler order: It is to walk along the tree, you can go backwards, the way through all the points is Euler order.

As pictured, it's Oura is 1-2-3-2-1-4-5-4-1

It is clear that the two-point LCA is the smallest point in the middle of their position in the Euler order, and if a point appears more than once in the Euler sequence, take a random one.
The Euler order length does not exceed twice times the number of points, when queried O (1).

#include <cmath> #include <cstdio> #include <algorithm> #define FO (i, x, y) for (int i = x; i <= y; i + +) #define FD (i, x, y) for (int i = x; i >= y; i-) #define MIN (A, B) ((a) < (b)?

(a): (b)) using namespace Std;
const int MAXN = 100005, maxc = 18;
int n, x, y;
int FINAL[MAXN], tot; struct Edge {int next, to;}

E[MAXN * 2];
int BZ[MAXN], DEP[MAXN], FA[MAXN], D[MAXN * 2], DT[MAXN], D0;

int A2[MAXC + 1], FJ[MAXC + 1][MAXN * 2];
    void link (int x, int y) {e[++ tot].next = final[x], e[tot].to = y, final[x] = tot;
e[++ Tot].next = Final[y], e[tot].to = x, final[y] = tot;
    } void DG (int x) {bz[x] = 1; d[++ D0] = x;
    DT[X] = D0;
        for (int k = final[x]; k; k = e[k].next) {int y = e[k].to; if (bz[y]) continue;
        Dep[y] = dep[x] + 1;
        Fa[y] = x;
        DG (y); d[++ D0] = x;
    DT[X] = D0;
    } void Init () {scanf ("%d", &n);
        Fo (i, 1, n-1) {scanf ("%d%d", &x, &y);
  Link (x, y);  } int Lca (int x, int y) {if (dt[x] > Dt[y]) swap (x, y);
    int lg = LOG2 (Dt[y]-dt[x] + 1); Return Dep[fj[lg][dt[x]]] < Dep[fj[lg][dt[y]-A2[LG] + 1]?
FJ[LG][DT[X]]: fj[lg][dt[y]-A2[LG] + 1];
    void Build () {a2[0] = 1; fo (i, 1, maxc) a2[i] = a2[i-1] * 2; DEP[1] = 1;
    DG (1);
    Fo (i, 1, d0) fj[0][i] = D[i]; Fo (j, 1, MAXC) fo (i, 1, d0) fj[j][i] = Dep[fj[j-1][i]] < Dep[fj[j-1][min (D0, i + a2[j-1])]?
Fj[j-1][i]: fj[j-1][min (D0, i + a2[j-1])];
    int main () {Init ();

    Build ();
    scanf ("%d%d", &x, &y);
printf ("%d", Lca (x, y));
 }
Tajan

That's the only way I'll be. A linear algorithm, in fact, its constant is a bit large, in the small data level may be slower than the log algorithm, Oi generally do not card, but it is true that the author said he will be a linear algorithm necessary algorithms (such as GDOI2017).
Process:
Hit the questions at two points.

Recursive, for the current node, first recursively ask for LCA within the subtree
Handle the query one by one hanging at this point, if another point on the inquiry has been traversed, the LCA is another point and the ancestor of the cluster is searched.
The father who set the current point in and out of the collection is the father of it in the tree.
Recursion ends.

Prove yourself to draw a picture and make a mess of it.

#include <cmath> #include <cstdio> #include <algorithm> #define FO (i, x, y) for (int i = x; i <= y; i + +) #define FD (i, x, y) for (int i = x; i >= y; i-) #define MIN (A, B) ((a) < (b)?

(a): (b)) using namespace Std;
const int MAXN = 100005, maxc = 18;
int n, x, Y, Q, ANS[MAXN], F[MAXN];
int FINAL[MAXN], tot, FINAL2[MAXN], Tot2; struct Edge {int Next, to, W;}

E[MAXN * 2], E2[MAXN * 2];

int BZ[MAXN], DEP[MAXN], FA[MAXN];

int find (int x) {return f[x] = = x: (F[x] = find (F[x));}
    void link (int x, int y) {e[++ tot].next = final[x], e[tot].to = y, final[x] = tot;
e[++ Tot].next = Final[y], e[tot].to = x, final[y] = tot;
    } void Link2 (int x, int y, int z) {e2[++ tot2].next = final2[x], e2[tot2].to = y, e2[tot2].w = z, final2[x] = Tot2;
e2[++ Tot2].next = Final2[y], e2[tot2].to = x, E2[TOT2].W = Z, final2[y] = Tot2;
    } void Init () {scanf ("%d", &n);
        Fo (i, 1, n-1) {scanf ("%d%d", &x, &y); Link (x, y);
    } void Build () {scanf ("%d", &q);
        Fo (i, 1, Q) {scanf ("%d%d", &x, &y);
    Link2 (x, y, i);
Fo (i, 1, n) f[i] = i;
    } void DG (int x) {bz[x] = 1;
    for (int k = final[x]; k; k = e[k].next) if (!bz[e[k].to)) DG (E[K].TO), f[e[k].to] = x;      
for (int k = final2[x], k; k = e2[k].next) if (bz[e2[k].to]) ANS[E2[K].W] = find (e2[k].to);
    int main () {Init ();
    Build ();
    DG (1);
 Fo (i, 1, Q) printf ("%d", ans[i]);
Sub-weight chain method

I believe that the students who have played the chain profile will.

#include <cmath> #include <cstdio> #include <algorithm> #define FO (i, x, y) for (int i = x; i <= y; i + +) #define FD (i, x, y) for (int i = x; i >= y; i-) #define MIN (A, B) ((a) < (b)?

(a): (b)) using namespace Std;
const int MAXN = 100005;
int n, x, Y, Q, ANS[MAXN], F[MAXN];
int FINAL[MAXN], tot; struct Edge {int next, to;}

E[MAXN * 2];

int BZ[MAXN], DEP[MAXN], FA[MAXN], SIZ[MAXN], SON[MAXN], TOP[MAXN];
    void link (int x, int y) {e[++ tot].next = final[x], e[tot].to = y, final[x] = tot;
e[++ Tot].next = Final[y], e[tot].to = x, final[y] = tot;
    } void Init () {scanf ("%d", &n);
        Fo (i, 1, n-1) {scanf ("%d%d", &x, &y);
    Link (x, y);
    } void DG (int x) {bz[x] = 1;
    SIZ[X] = 1;
        for (int k = final[x]; k; k = e[k].next) {int y = e[k].to; if (bz[y]) continue;
        Dep[y] = dep[x] + 1;
        Fa[y] = x;
        DG (y);
        SIZ[X] + = Siz[y]; if (Siz[y] > Siz[son[x]]) son[x] = y;
    } Bz[x] = 0;
    } void Dg2 (int x) {bz[x] = 1;
    if (top[x] = = 0) top[x] = x;
    if (Son[x]!= 0) top[son[x] = Top[x], DG2 (son[x));
        for (int k = final[x]; k; k = e[k].next) {int y = e[k].to; if (bz[y]) continue;
    Dg2 (y); {LCA (int x, int y) {while (top[x]!= top[y]) if (dep[top[x)] >= dep[top[y]) x = fa[top[x]]; else y
    = Fa[top[y]]; return dep[x] < Dep[y]?
x:y;
    } void End () {scanf ("%d", &q);
        Fo (i, 1, Q) {scanf ("%d%d", &x, &y);
    printf ("%d", Lca (x, y));
    int main () {Init (); DEP[1] = 1;
    DG (1);

    DG2 (1);
End ();
 }
Time Comparison:

With 1000000 random data evaluation results:
multiple points of LCA

Is the least of the depth of the LCA of one point to all other points, the perceptual proof.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.