[codeforces 528]A. Glass Carving

[codeforces 528]A. Glass Carving

试题描述

Leonid wants to become a glass carver (the person who creates beautiful artworks by cutting the glass). He already has a rectangular wmm  ×  h mm sheet of glass, a diamond glass cutter and lots of enthusiasm. What he lacks is understanding of what to carve and how.

In order not to waste time, he decided to practice the technique of carving. To do this, he makes vertical and horizontal cuts through the entire sheet. This process results in making smaller rectangular fragments of glass. Leonid does not move the newly made glass fragments. In particular, a cut divides each fragment of glass that it goes through into smaller fragments.

After each cut Leonid tries to determine what area the largest of the currently available glass fragments has. Since there appear more and more fragments, this question takes him more and more time and distracts him from the fascinating process.

Leonid offers to divide the labor — he will cut glass, and you will calculate the area of the maximum fragment after each cut. Do you agree?

输入

The first line contains three integers w, h, n (2 ≤ w, h ≤ 200 000, 1 ≤ n ≤ 200 000).

Next n lines contain the descriptions of the cuts. Each description has the form H y or V x. In the first case Leonid makes the horizontal cut at the distance y millimeters (1 ≤ y ≤ h - 1) from the lower edge of the original sheet of glass. In the second case Leonid makes a vertical cut at distance x (1 ≤ x ≤ w - 1) millimeters from the left edge of the original sheet of glass. It is guaranteed that Leonid won't make two identical cuts.

输出

After each cut print on a single line the area of the maximum available glass fragment in mm2.

输入示例

H
V
V
V

输出示例


数据规模及约定

见“输入

题解

不难发现对于任意的长、宽,我们都可以还原出原玻璃板上的一个矩形,所以求最大面积可以转化为分别求最大的长和宽,然后乘起来就是答案。

问题变成了一个一维的:每次在 [0, n] 这个区间内插入不重复的点并询问最长的不包含任何点的线段。不难想到平衡树,因为它可以维护一个点的前驱和后继(不妨设这是平衡树 1 号),那么如何实时维护最长线段呢?我们可以再建一棵平衡树(平衡树 2 号)维护每条线段的长度,那么一次插入操作(插入点 x)不仅要在 1 号中插入一个数并找到其前驱 l 和后继 r,还要在 2 号中删除 r - l 这个长度,并添加 x - l 和 r - x 这两个长度,维护最大值即可。因为要分别维护矩形的长和宽,所以总共要建立 4 棵平衡树。(感觉好有毒。。。)

对于其他人,这题是 STL 水题;对于我,这题是数据结构码农题。。。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 1000010
#define LL long long
int n, m, q; struct Node {
int v, r, mn, mx;
Node(): v(0), r(0), mn(0), mx(0) {}
Node(int _, int __, int ___, int ____): v(_), r(__), mn(___), mx(____) {}
} ns[maxn];
int r1, r2, r3, r4, ch[maxn][2], fa[maxn], ToT;
void maintain(int o) {
int l = ch[o][0], r = ch[o][1];
ns[o].mn = ns[o].mx = ns[o].v;
if(l) ns[o].mn = min(ns[o].mn, ns[l].mn), ns[o].mx = max(ns[o].mx, ns[l].mx);
if(r) ns[o].mn = min(ns[o].mn, ns[r].mn), ns[o].mx = max(ns[o].mx, ns[r].mx);
return ;
}
void rotate(int u) {
int y = fa[u], z = fa[y], l = 0, r = 1;
if(ch[y][1] == u) swap(l, r);
if(z) ch[z][ch[z][1]==y] = u;
fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
ch[y][l] = ch[u][r]; ch[u][r] = y;
maintain(y); maintain(u);
return ;
}
int xl, xr;
void insert(int& o, int v) {
if(!o) ns[o = ++ToT] = Node(v, rand(), v, v);
else {
int d = (v >= ns[o].v);
// printf("%d %d %d\n", ns[o].v, v, ns[ch[o][d]].mn);
// printf("%d %d %d\n", ns[ch[o][d]].mx, v, ns[o].v);
if(v >= ns[o].v && v <= ns[ch[o][d]].mn) xl = max(xl, ns[o].v), xr = min(xr, ns[ch[o][d]].mn);
if(v <= ns[o].v && v >= ns[ch[o][d]].mx) xl = max(xl, ns[ch[o][d]].mx), xr = min(xr, ns[o].v);
insert(ch[o][d], v);
fa[ch[o][d]] = o;
// printf("bo: %d %d\n", o, ch[o][d]);
if(ns[ch[o][d]].r > ns[o].r) {
int t = ch[o][d];
rotate(ch[o][d]);
o = t;
}
// printf("ao: %d\n", o);
}
return maintain(o);
}
bool del(int& o, int v, int pa) {
if(!o) return 1;
// printf("del: %d %d %d\n", o, ns[o].v, v);
if(ns[o].v == v) {
if(!ch[o][0] && !ch[o][1]) {
fa[o] = ch[o][0] = ch[o][1] = 0, o = 0;
maintain(o);
return 0;
}
if(!ch[o][0]) {
int t = ch[o][1];
fa[o] = ch[o][0] = ch[o][1] = 0, o = t, fa[o] = pa;
maintain(o);
return 0;
}
if(!ch[o][1]) {
int t = ch[o][0];
fa[o] = ch[o][0] = ch[o][1] = 0, o = t, fa[o] = pa;
maintain(o);
return 0;
}
int d = ns[ch[o][1]].r > ns[ch[o][0]].r;
int t = ch[o][d];
rotate(ch[o][d]);
o = t;
del(ch[o][d^1], v, o);
maintain(o);
return 0;
}
int d = (v >= ns[o].v);
if(del(ch[o][d], v, o)) maintain(o), del(ch[o][d^1], v, o);
maintain(o);
return 0;
} int main() {
srand(6);
n = read(); m = read(); q = read(); insert(r1, 0); insert(r1, m);
insert(r2, 0); insert(r2, n);
insert(r3, m); insert(r4, n);
while(q--) {
char tp = getchar();
while(!isalpha(tp)) tp = getchar();
int x = read();
xl = -1; xr = max(n, m) + 1;
if(tp == 'H') {
insert(r1, x);
int l = xl, r = xr;
// printf("f %d %d\n", l, r);
del(r3, r - l, 0);
insert(r3, x - l), insert(r3, r - x);
}
if(tp == 'V') {
insert(r2, x);
int l = xl, r = xr;
// printf("f %d %d\n", l, r);
del(r4, r - l, 0);
insert(r4, x - l), insert(r4, r - x);
}
printf("%I64d\n", (LL)ns[r3].mx * ns[r4].mx);
} return 0;
}
上一篇:Codeforces Round #296 (Div. 2) C. Glass Carving [ set+multiset ]


下一篇:codeforces 527 C Glass Carving