LGP11261 [COTS 2018] 直方图 学习笔记

LGP11261 [COTS 2018] 直方图 学习笔记

Luogu Link

前言

参考了这篇题解。算是对其更详细的一个解释。

题意简述

给定一宽为 \(n\) 的直方图,第 \(i\) 格的高度为 \(a_i\)

给定正整数 \(S\),求出满足以下条件的网格矩形的数量:

  • 有一条边在 \(x\) 轴上。
  • 完全位于直方图内部。
  • 面积至少为 \(S\)

\(n\le 10^5,a_i\le 10^9,S\le 10^{14}\)

做法解析

要求的矩形都形如 \((l,0),(r,0),(r,h_u),(l,h_u)\)

确定矩形的高 \(b\) 就随之确定了 \(a\ge \lceil \frac{S}{b} \rceil\)

我们发现,当矩形的 \(l,r\) 确定之后,限制 \(h_u\) 范围的正是 \([l,r]\)\(a_i\) 的最小值。此时套路来了:我们以 \(u\) 为键,\(h_u\) 为值建一棵小根笛卡尔树,并考虑横跨每个最小值的贡献。具体来说我们对这棵笛卡尔树做一遍 \(dfs\),每搜到一个结点 \((u,h_u)\),设其在笛卡尔树上管辖的区间为 \([lb_u,rb_u]\),我们就统计所有 \(lb_u\le l\le u,u\le r\le rb_u\) 的合法矩形的数量。这么做可以不重不漏地计数。

pV5iYEF.png

\(L=u-lb,R=u-rb\),现在答案可以写作:

\[\sum_u\sum_{i=0}^{L}\sum_{j=0}^{R} \max(h_u-\lceil\frac{S}{i+j+1}\rceil+1,0) \]

其中的 \(\lceil\frac{S}{i+j+1}\rceil\) 代表着 \(i,j\) 确定后合法矩形高度的最小值,\(a_u-\lceil\frac{S}{i+j+1}\rceil+1\) 则自然是 \(i,j\) 确定后合法高度的种类。

由启发式合并思想,为了保证复杂度,考虑枚举较小的那一侧子树的 \(i\),此处不妨设 \(L<R\)。我们又让第二维改为枚举矩形的长度,上式现在可以写作:

\[\sum_{i=0}^{L}\sum_{k=i+1}^{i+R+1}\max(a_u-\lceil\frac{S}{k}\rceil+1,0) \]

又:\(a_u-\lceil\frac{S}{k}\rceil+1\ge 0\)\(\lceil\frac{S}{k}\rceil\le a_u+1\)

显然最小的满足 \(\lceil\frac{S}{k}\rceil\le a_u+1\)\(k\) 就是 \(\lceil\frac{S}{a_u+1}\rceil\)

\(\lceil\frac{S}{x}\rceil\le y\to xy\ge S\to x\ge\lceil\frac{S}{y}\rceil\)

就是这样,稍微写一句以防我忘了。

\(k_0=\max(i+1,\lceil\frac{S}{a_u+1}\rceil)\),则上式等价于

\[\sum_{i=0}^{L}\sum_{k=k_0}^{i+R+1} a_u-\lceil\frac{S}{k}\rceil+1 \]

也即等价于

\[\sum_{i=0}^L (i+R+1-k_0+1)\times (a_u+1)-\sum_{k=k_0}^{i+R+1} \lceil \frac{S}{i} \rceil \]

最后减去的那一坨东西,通过预处理 \(\lceil \frac{S}{i} \rceil\) 的前缀和即可快速求值。这道题就做完了!

时间复杂度 \(O(n\log n)\)

代码实现

代码很简单!

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=1e5+5;
int N;lolo A[MaxN],S,pre[MaxN],ans;
int ls[MaxN],rs[MaxN],stk[MaxN],ktp;
lolo calc(int u,int ci,int rs){
    lolo cl=max(lolo(ci+1),pcedi(S,A[u]+1));
    lolo cr=ci+rs+1;if(cl>cr)return 0;
    return (cr-cl+1)*(A[u]+1)-(pre[cr]-pre[cl-1]);
}
void solve(int u,int cl,int cr){
    int lsiz=u-cl,rsiz=cr-u;
    if(lsiz>rsiz)swap(lsiz,rsiz);
    for(int i=0;i<=lsiz;i++)ans+=calc(u,i,rsiz);
    if(ls[u])solve(ls[u],cl,u-1);
    if(rs[u])solve(rs[u],u+1,cr);
}
int main(){
    readis(N,S);
    for(int i=1;i<=N;i++)pre[i]=pre[i-1]+pcedi(S,lolo(i));
    for(int i=1;i<=N;i++)readi(A[i]);
    for(int i=1,k;i<=N;i++){
        k=ktp;
        while(k&&A[stk[k]]>A[i])k--;
        if(k)rs[stk[k]]=i;
        if(k<ktp)ls[i]=stk[k+1];
        stk[++k]=i,ktp=k;
    }
    solve(stk[1],1,N),writi(ans);
    return 0;
}

反思总结

我们考虑有顺序地枚举限制矩形高度的 \(h_i\),于是把问题搬到了笛卡尔树上!

这是什么?这是“极值分治”的思想。其过程就是建笛卡尔树的过程。

posted @ 2025-02-16 17:05  矞龙OrinLoong  阅读(15)  评论(2)    收藏  举报