LCA题目选讲2

[LightOJ 1128]Greatest Parent

这道题我们直接按照给出的父亲节点信息直接处理出倍增用的数组,然后直接倍增解决问题即可

[BZOJ 2144]跳跳棋

我们发现一种状态的转移只有三种,中间元素向两边跳两种和两边元素,所以我们把中间元素向左跳做左儿子,向右跳做右儿子,两边向中间跳作为他的父亲节点。我们发现当中间点恰好是两边点的中点的时候它没有父亲节点,即为根节点。

我们跳到两种状态的根节点,看是否能够转移。

然后二分答案,求出LCA的高度最后得到解

看代码理解更佳

#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;

int read() {
    int a = 0, x = 1;
    char ch = getchar();
    while (ch > '9' || ch < '0') {
        if (ch == '-')
            x = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        a = a * 10 + ch - '0';
        ch = getchar();
    }
    return a * x;
}
struct node {
    int a[4];
    friend bool operator!=(node a, node b) {
        for (int i = 1; i <= 3; i++)
            if (a.a[i] != b.a[i])
                return true;
        return false;
    }
    friend bool operator==(node a, node b) { return !(a != b); }
    void print() { printf("%lld %lld %lld
", a[1], a[2], a[3]); }
} A, B;
const int inf = 1e18;
node r1, r2;
int temp = 0, dep1, dep2;
node find(node S, int k) {
    int z1 = S.a[2] - S.a[1], z2 = S.a[3] - S.a[2], tmp;
    if (z1 > z2) {
        tmp = min((z1 - 1) / z2, k);
        z1 -= tmp * z2;
        temp += tmp;
        k -= tmp;
        S.a[2] -= tmp * z2, S.a[3] -= tmp * z2;
    } else if (z1 < z2) {
        tmp = min((z2 - 1) / z1, k);
        z2 -= tmp * z2;
        k -= tmp;
        temp += tmp;
        S.a[1] += tmp * z1, S.a[2] += tmp * z1;
    }
    if (z1 == z2)
        return S;
    if (k)
        return find(S, k);
    return S;
}

signed main() {
    for (int i = 1; i <= 3; i++) A.a[i] = read();
    for (int i = 1; i <= 3; i++) B.a[i] = read();
    sort(A.a + 1, A.a + 4);
    sort(B.a + 1, B.a + 4);
    r1 = find(A, inf);
    dep1 = temp, temp = 0;
    r2 = find(B, inf);
    dep2 = temp, temp = 0;
    if (r1 != r2) {
        printf("NO");
        return 0;
    }
    if (dep1 < dep2) {
        swap(dep1, dep2);
        swap(A, B);
    }
    A = find(A, dep1 - dep2);
    int l = 0, r = dep2, mid;
    while (l != r) {
        mid = l + r >> 1;
        if (find(A, mid) == find(B, mid))
            r = mid;
        else
            l = mid + 1;
    }
    printf("YES
%lld", l * 2 + (dep1 - dep2));
    return 0;
}
原文地址:https://www.cnblogs.com/nao-nao/p/13712369.html