洛谷P16762 [GKS 2020 #D] Locked Doors 题解 笛卡尔树+LCA

题目链接:https://www.luogu.com.cn/problem/P16762

解题思路完全来自 GX6zm大佬的博客

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;

int T, n, Q, idx, D[maxn], ls[maxn], rs[maxn], rt, lb[maxn], rb[maxn], fa[maxn][18];

void init() {
    fill(ls+1, ls+n, 0);
    fill(rs+1, rs+n, 0);
    idx = n;
}

void dfs(int &u, int p, int l, int r) {
    if (!u) {
        u = idx++;
    }
    fa[u][0] = p;
    lb[u] = l;
    rb[u] = r;
    if (u < n) {
        dfs(ls[u], u, l, u);
        dfs(rs[u], u, u+1, r);
    }
}

int cal(int s, int k) {
    if (k == 1) return s;
    int u = n - 1 + s;
    for (int i = 17; i >= 0; i--) {
        int p = fa[u][i];
        if (rb[p] - lb[p] + 1 < k)
            u = p;
    }
    int p = fa[u][0];
    int cnt = k - (rb[u] - lb[u] + 1);
    if (lb[u] == lb[p]) return p + cnt;
    return p + 1 - cnt;
}

void solve() {
    stack<int> stk;
    for (int i = 1; i < n; i++) {
        int last = 0;
        while (!stk.empty() && D[stk.top()] < D[i]) {
            last = stk.top();
            stk.pop();
        }
        if (!stk.empty()) rs[stk.top()] = i;
        else rt = i;
        ls[i] = last;
        stk.push(i);
    }
    dfs(rt, rt, 1, n);
    assert(idx == 2 * n);
    for (int i = 1; i <= 17; i++)
        for (int u = 1; u < 2*n; u++)
            fa[u][i] = fa[ fa[u][i-1] ][i-1];
    while (Q--) {
        int s, k;
        scanf("%d%d", &s, &k);
        int ans = cal(s, k);
        printf(" %d", ans);
    }
    putchar('\n');
}

int main() {
    scanf("%d", &T);
    for (int cas = 1; cas <= T; cas++) {
        printf("Case #%d:", cas);
        scanf("%d%d", &n, &Q);
        init();
        for (int i = 1; i < n; i++)
            scanf("%d", D+i);
        solve();
    }
    return 0;
}
posted @ 2026-09-05 08:32  quanjun  阅读(12)  评论(0)    收藏  举报