洛谷P11261 [COTS 2018] 直方图 Histogram 题解 笛卡尔树+启发式合并

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

解题思路:完全来自 OrinLoong 大佬的博客。

示例程序:

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

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

void init() {
    for (int i = 1; i <= n; i++)
        sum[i] = sum[i-1] + (p - 1) / 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) {    // 枚举左边一段的长度(左端点)
        for (int i = 0; i <= u-l; i++) {
            int L = max(i+1ll, (p-1)/a[u]+1), R = r - u + 1 + i;
            if (L <= R) {
                ans += 1ll * (R - L + 1) * a[u] - (sum[R] - sum[L-1]);
            }
        }
    }
    else {  // 枚举右边一段的长度(右端点)
        for (int i = 0; i <= r-u; i++) {
            int L = max(i+1ll, (p-1)/a[u]+1), R = u - l + 1 + i;
            if (L <= R) {
                ans += 1ll * (R - L + 1) * a[u] - (sum[R] - sum[L-1]);
            }
        }
    }
}

void solve() {
    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);
    }
    dfs(rt, 1, n);
    printf("%lld\n", ans);
}

int main() {
    scanf("%d%lld", &n, &p);
    for (int i = 1; i <= n; i++)
        scanf("%d", a+i);
    init();
    solve();
    return 0;
}
posted @ 2026-09-06 15:22  quanjun  阅读(11)  评论(0)    收藏  举报