洛谷 P4198 楼房重建

洛谷传送门

一道线段树维护区间前缀最大值个数的好题。

思路

易得连接 (0,0),(i,Hi) 的线段斜率为 si=Hii。则题要求的就是满足 i[1,n],si>maxj=1i1sji 的个数。考虑线段树维护。

线段树上每个结点维护当前区间 [l,r] 的斜率 max只考虑 [l,r] 的前缀最大值个数 cnt,即不考虑 [1,l1][l,r] 的影响。max pushup 是很容易的,对左、右儿子取 max 即可。考虑 cnt 怎么 pushup

引入一个新函数 calc(rt, l, r, x),它返回区间 [l,r] 内,假设 [1,l1] 的前缀最大值为 x[l,r] 内的 cnt

  • rt 为叶子结点,若 x<si 返回 1,否则返回 0。显然。
  • rt 为非叶子结点,考虑左右子树两部分贡献分别计算。若 x<maxls,则左子树的贡献为 calc(ls, l, mid, x),右子树的贡献为 cntrtcntls。因为在右子树中相当于前缀 max 为左子树的 max,因此 cnt 的贡献直接相减即可得到。若 xmaxls,则左子树的贡献为 0,右子树的贡献为 calc(rs, mid + 1, r, x)

现在可以回头解决 pushup 的问题了:cntrt=cntlsrt+calc(rs,mid+1,r,maxls)。左子树的 cnt 可以直接继承,因为左子树的区间为当前子树的区间的前缀;右子树的 cnt 就利用 calc 计算。由于是只考虑 [l,r] 区间的,所以 x 设为 maxls 就行。

时间复杂度 O(mlog2n)

代码

code
/*
p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy
*/
#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
using namespace std;
typedef long long ll;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 100100;
ll n, m, a[maxn];
struct treenode {
ldb mx;
int cnt;
} tree[maxn << 2];
int calc(int rt, int l, int r, ldb x) {
if (l == r) {
return (x < (ldb)a[l] / l ? 1 : 0);
}
int mid = (l + r) >> 1;
if (x < tree[rt << 1].mx) {
return calc(rt << 1, l, mid, x) + tree[rt].cnt - tree[rt << 1].cnt;
} else {
return calc(rt << 1 | 1, mid + 1, r, x);
}
}
void pushup(int x, int l, int r) {
int mid = (l + r) >> 1;
tree[x].mx = max(tree[x << 1].mx, tree[x << 1 | 1].mx);
tree[x].cnt = tree[x << 1].cnt + calc(x << 1 | 1, mid + 1, r, tree[x << 1].mx);
}
void update(int rt, int l, int r, int x) {
if (l == r) {
tree[rt].mx = (ldb)a[l] / l;
tree[rt].cnt = 1;
return;
}
int mid = (l + r) >> 1;
if (x <= mid) {
update(rt << 1, l, mid, x);
} else {
update(rt << 1 | 1, mid + 1, r, x);
}
pushup(rt, l, r);
}
void solve() {
scanf("%lld%lld", &n, &m);
while (m--) {
ll x, y;
scanf("%lld%lld", &x, &y);
a[x] = y;
update(1, 1, n, x);
printf("%d\n", tree[1].cnt);
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
posted @   zltzlt  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示