CF527C Glass Carving(线段树)

题目

有一块 w ∗ h w*h wh的玻璃,每次横着切一刀( H H H)或者竖着切一刀( V V V),没有两次相同的切割,求最大的矩形碎片面积。 样例中第一行是 w , h w,h w,h(玻璃大小)和 n n n(切割次数),字母后的数字表示距下边缘( H H H)/左边缘( V V V)的距离

题解

  • 我们可以把长和宽看做 01 01 01序列,起初全部为 0 0 0, 而每切一刀对应把相应位置的 0 0 0变为 1 1 1。若我们要求最大子矩阵的面积,我们只需知道最长的连续为 0 0 0的长度即可。 这个显然可以线段树维护,类比最大连续子段和的维护方式即可。

code

#include <bits/stdc++.h> 
using namespace std; 
const int maxn = 2e5 + 100; 
typedef long long LL; 

template <class T> 
inline void read(T &s) {
	s = 0; T w = 1, ch = getchar(); 
	while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
	while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
	s *= w; 
}

int w, h, n; 
struct node {
	int l, r; 
	LL lmax, rmax, dat; 
	bool flag; 
}; 
struct SegT {
	node t[maxn << 2]; 

	inline void push_up(int p) {
		t[p].flag = t[p<<1].flag && t[p<<1|1].flag; 
		t[p].dat = max(max(t[p<<1].dat, t[p<<1|1].dat), t[p<<1].rmax + t[p<<1|1].lmax); 
		t[p].lmax = t[p<<1].flag ? t[p<<1].dat + t[p<<1|1].lmax : t[p<<1].lmax; 
		t[p].rmax = t[p<<1|1].flag ? t[p<<1|1].dat + t[p<<1].rmax : t[p<<1|1].rmax; 
	}

	inline void build(int p, int l, int r) {
		t[p].l = l, t[p].r = r; 
		if (l == r) {
			t[p].lmax = 1, t[p].rmax = 1, t[p].dat = 1, t[p].flag = 1; 
			return ; 
		}
		int mid = (l + r) >> 1; 
		build(p<<1, l, mid); 
		build(p<<1|1, mid + 1, r); 
		push_up(p); 
	}

	inline void update(int p, int x) {
		if (t[p].l == t[p].r) {
			t[p].lmax = 0, t[p].rmax = 0, t[p].dat = 0, t[p].flag = 0; 
			return ; 
		}
		int mid = (t[p].l + t[p].r) >> 1; 
		if (x <= mid) update(p<<1, x); 
		else update(p<<1|1, x); 
		push_up(p); 
	}
}H, W; 

int main() {
	read(w), read(h), read(n); 
	W.build(1, 1, w - 1); 
	H.build(1, 1, h - 1); 
	for (int i = 1; i <= n; ++i) {
		char opt[2]; int x; 
		scanf("%s%d", opt, &x); 
		if (opt[0] == 'H') {
			H.update(1, x); 
		}
		else {
			W.update(1, x); 
		}
		LL ret = 1ll * (H.t[1].dat + 1) * (W.t[1].dat + 1); 
		printf("%lld\n", ret); 
	}
	return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值