题意:给定一个矩形,每次可以横向切割或纵向切割,求每次切割完后所有矩形的最大面积
思路:最大矩形的面积 = 最大的w * 最大的h,所以可以键两棵线段树,一棵维护最大的w,一棵维护最大的h,以维护最大的w为例:
我们可以把W - 1个划分点作为线段树的叶子,每个点如果被划分就设为1, 没有划分设为0,那么最长的w就是线段树统计出的最长的连续0的个数+1.
因为最长连续0不符合区间加法,所以要对线段树维护的区间信息进行扩充,即维护这个区间【从左边开始的连续0的数量】,【从右边开始的连续0的数量】,【是否全部为0】,【最大连续0四个量】。
为什么要这么扩充?,下面来看一下一个区间的最大连续0是如何通过两个子区间求出:
相信大家都接触过分治法求最大连续和,原理是一样的,一个区间的【最大连续0】 = max(左区间的最大连续0, 右区间的最大连续0,跨越中间的最大连续0)
左右区间的最大连续0递归就可以
跨越中间的最大连续0 = 左区间【从右边开始的连续0】 + 右区间【从左开始的连续0】,为了求跨越中间的最大连续0我们的线段树要维护这两个量
那么【是否全为0】这个信息是干什么的呢?他是用来更新【从左边开始的连续0】以及【从右边开始的连续0】的
一个区间【从左边开始的连续0】 = 左区间【从左边开始的连续0】 + (左区间是否全为0) ? 右区间【从左边开始的连续0】 : 0
一个区间【从右边开始的连续0】 = 右区间【从右边开始的连续0】 + (右区间是否全为0) ? 左区间【从右边开始的连续0】 : 0
至此区间信息就完全了,可以用线段树求解了
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2 * 1e5 + 10;
struct SegTree {
ll ls, rs, max0;
bool is_all0;
}segTree[2][maxn<<2];
void pushup(int root, int flag) {
SegTree &cur = segTree[flag][root], &lc = segTree[flag][root<<1], &rc = segTree[flag][root<<1|1];
cur.ls = lc.ls + (lc.is_all0 ? rc.ls : 0);
cur.rs = rc.rs + (rc.is_all0 ? lc.rs : 0);
cur.max0 = max(lc.rs + rc.ls, max(lc.max0, rc.max0));
cur.is_all0 = lc.is_all0 && rc.is_all0;
}
void build(int L, int R, int root, int flag) {
if (L == R) {
segTree[flag][root].ls = segTree[flag][root].rs = segTree[flag][root].max0 = 1;
segTree[flag][root].is_all0 = true;
return;
}
int mid = (L + R)>>1;
build(L, mid, root<<1, flag);
build(mid + 1, R, root<<1|1, flag);
pushup(root, flag);
}
void update_node(int L, int R, int root, int pos, int flag) {
if (L == R) {
segTree[flag][root].ls = segTree[flag][root].rs = segTree[flag][root].max0 = 0;
segTree[flag][root].is_all0 = false;
return;
}
int mid = (L + R)>>1;
if (pos <= mid) {
update_node(L, mid, root<<1, pos, flag);
}
else {
update_node(mid + 1, R, root<<1|1, pos, flag);
}
pushup(root, flag);
}
ll query(int L, int R, int root, int qL, int qR, int flag) {
if (qL <= L && R <= qR) {
return segTree[flag][root].max0;
}
int mid = (L + R)>>1;
ll temp = 0;
if (qL <= mid) {
temp = max(temp, query(L, mid, root<<1, qL, qR, flag));
}
if (qR > mid) {
temp = max(temp, query(mid + 1, R, root<<1|1, qL, qR, flag));
}
return temp;
}
int main()
{
int W, H, q, x;
char c[5];
while (scanf("%d %d %d", &W, &H, &q) == 3) {
build(1, W - 1, 1, 0);
build(1, H - 1, 1, 1);
while (q--) {
scanf("%s %d", c, &x);
if (c[0] == 'V') {
update_node(1, W - 1, 1, x, 0);
}
else {
update_node(1, H - 1, 1, x, 1);
}
printf("%I64d\n", (query(1, W - 1, 1, 1, W - 1, 0) + 1) * (query(1, H - 1, 1, 1, H - 1, 1) + 1));
}
}
}