其他分享
首页 > 其他分享> > 洛谷 P4198 楼房重建

洛谷 P4198 楼房重建

作者:互联网

洛谷传送门

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

思路

易得连接 \((0,0),(i,H_i)\) 的线段斜率为 \(s_i = \frac{H_i}{i}\)。则题要求的就是满足 \(i \in [1,n], s_i > \max\limits_{j=1}^{i-1} s_j\) 的 \(i\) 的个数。考虑线段树维护。

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

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

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

时间复杂度 \(O(m \log^2 n)\)。

代码

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;
}

标签:rt,左子,cnt,洛谷,楼房,P4198,ls,max,calc
来源: https://www.cnblogs.com/zltzlt-blog/p/16484860.html