题目
有一块 w ∗ h w*h w∗h的玻璃,每次横着切一刀( 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;
}