楼房重建线段树

维护前缀最大值个数。

pushup 操作进行修改。

定义 solve(x, lim) 为前面这个区间的最大值为 limx 支配的区间产生的贡献。

如果 x 的最大值已经小于 lim,显然没有贡献。

考虑 x 的左儿子,如果左儿子的最大值大于 lim 直接递归左二子查询,此时右儿子的答案不受影响。

如果左儿子最大值小于 lim 的话,贡献显然为0,递归右儿子查询。

solve 每次只会递归一个儿子,一共 O(logn) 层,复杂度 O(logn)

总复杂度 O(nlog2n)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5, INF = 0x3f3f3f3f;
const LL mod = 998244353;

int n, m;

struct Segment_Tree {
	struct Node {
		int l, r, val;
		double maxv;
		#define l(x) tr[x].l
		#define r(x) tr[x].r
		#define val(x) tr[x].val
		#define mx(x) tr[x].maxv
	} tr[N << 2];

	void build(int l, int r, int x) {
		tr[x] = {l, r};
		if (l == r) return;
		int mid = (l + r) / 2;
		build(l, mid, x * 2), build(mid + 1, r, x * 2 + 1);
	}

	int solve(int x, double lim) {
		if (mx(x) <= lim) return 0;
		if (l(x) == r(x)) return 1;
		if (mx(x * 2) <= lim) return solve(x * 2 + 1, lim);
		else return solve(x * 2, lim) + val(x) - val(x * 2);
	}

	void pushup(int x) {
		mx(x) = max(mx(x * 2), mx(x * 2 + 1));
		val(x) = val(x * 2) + solve(x * 2 + 1, mx(x * 2));
	}

	void update(int p, int x, double v) {
		if (l(x) == r(x)) {
			mx(x) = v;
			val(x) = 1;
			return;
		}
		int mid = (l(x) + r(x)) / 2;
		if (p <= mid) update(p, x * 2, v);
		else update(p, x * 2 + 1, v);
		pushup(x);
	}

} SegT;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);

    cin >> n >> m;
    SegT.build(1, n, 1);

    for (int i = 1; i <= m; i ++) {
    	int x, y;
    	cin >> x >> y;
    	SegT.update(x, 1, (double)y / x);
    	cout << SegT.val(1) << '\n';
    }

    return 0;
}
posted @   Svemit  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
主题色彩