洛谷P4755 Beautiful Pair 题解 笛卡尔树+启发式合并+线段树合并

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

解题思路:参考自 Find_NICK大佬的博客。

示例程序:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e5 + 5, inf = 1e9, maxm = maxn * 50;

struct Segt {

    int tr[maxm], ls[maxm], rs[maxm], idx;

    void push_up(int u) {
        tr[u] = tr[ ls[u] ] + tr[ rs[u] ];
    }

    void add(int p, int v, int l, int r, int &u) {
        if (!u) u = ++idx;
        if (l == r) {
            tr[u] += v;
            return;
        }
        int mid = (l + r) >> 1;
        (p <= mid) ? add(p, v, l, mid, ls[u]) : add(p, v, mid+1, r, rs[u]);
        push_up(u);
    }

    int Merge(int u, int v, int l, int r) {
        if (!u || !v) return u + v;
        tr[u] += tr[v];
        if (l == r)
            return u;
        int mid = (l + r) >> 1;
        ls[u] = Merge(ls[u], ls[v], l, mid);
        rs[u] = Merge(rs[u], rs[v], mid+1, r);
        return u;
    }

    int query(int L, int R, int l, int r, int u) {
        if (!u) return 0;
        if (L <= l && r <= R)
            return tr[u];
        int res = 0, mid = (l + r) >> 1;
        if (L <= mid) res += query(L, R, l, mid, ls[u]);
        if (R > mid) res += query(L, R, mid+1, r, rs[u]);
        return res;
    }

} segt;

int n, a[maxn], root[maxn], ls[maxn], rs[maxn], rt;
ll ans;

void di_ka_er() {
    stack<int> stk;
    for (int i = 1; i <= n; i++) {
        int last = 0;
        while (!stk.empty() && a[stk.top()] < a[i]) {
            last = stk.top();
            stk.pop();
        }
        if (!stk.empty()) rs[stk.top()] = i;
        else rt = i;
        ls[i] = last;
        stk.push(i);
    }
}

void dfs(int u, int l, int r) {
    if (!u)
        return;
    dfs(ls[u], l, u-1);
    dfs(rs[u], u+1, r);
    if (u - l < r - u) {
        root[u] = root[ rs[u] ];
        segt.add(a[u], 1, 1, inf, root[u]);
        for (int i = l; i <= u; i++) {
            ans += segt.query(1, a[u]/a[i], 1, inf, root[u]);
        }
        segt.Merge(root[u], root[ ls[u] ], 1, inf);
    }
    else {
        root[u] = root[ ls[u] ];
        segt.add(a[u], 1, 1, inf, root[u]);
        for (int i = u; i <= r; i++) {
            ans += segt.query(1, a[u]/a[i], 1, inf, root[u]);
        }
        segt.Merge(root[u], root[ rs[u] ], 1, inf);
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", a+i);
    di_ka_er();
    dfs(rt, 1, n);
    printf("%lld\n", ans);
    return 0;
}
posted @ 2026-09-05 16:15  quanjun  阅读(11)  评论(0)    收藏  举报