USACO 08 Feb. Gold C Hotel
POJ3667 BZOJ1593 洛谷2894
线段树
学线段树时,过了惰性标记后的下一个坎:区间合并与拆分。
每个结点上,除了要存该区间内空闲区间的最大长度,还要多维护两个值:从左/右端数起的空闲区间的长度。
查找最左端的长度≥x的区间时:
- 如果该结点的
程序中有大量重复,所以有多处重构。
#include <cstdio>
const int MAXN = 5e4;
char ch; int integer;
int readint() {
while ((ch = getchar()) < '0' || ch > '9');
integer = 0;
do {
integer = (integer << 3) + (integer << 1) + ch - '0';
} while ((ch = getchar()) >= '0' && ch <= '9');
return integer;
}
int max(const int &a, const int &b, const int &c) {
if (a > b)
return a > c ? a : c;
return b > c ? b : c;
}
struct TreeNode {
int lb, rb, size, cmax, lmax, rmax;
TreeNode *lc, *rc;
TreeNode() {}
TreeNode(int lb, int rb, int sz, TreeNode *lc, TreeNode *rc) :
lb(lb), rb(rb), size(sz), cmax(sz), lmax(sz), rmax(sz), lc(lc), rc(rc) {}
}tree[1 << 17], *new_node = tree;
TreeNode* build_tree(int l, int r) {
if (l == r)
*new_node = TreeNode(l, r, r - l + 1, NULL, NULL);
else {
TreeNode *tmplc = build_tree(l, l + r >> 1);
TreeNode *tmprc = build_tree((l + r >> 1) + 1, r);
*new_node = TreeNode(l, r, r - l + 1, tmplc, tmprc);
}
return new_node++;
}
int x, d;
bool is_full(TreeNode *node) {
return node->cmax == 0;
}
bool is_empty(TreeNode *node) {
return node->cmax == node->size;
}
void node_fill(TreeNode *node) {
node->cmax = node->lmax = node->rmax = 0;
}
void node_empty(TreeNode *node) {
node->cmax = node->lmax = node->rmax = node->size;
}
void propagate(TreeNode *node) { //标记下传
if (is_empty(node)) {
node_empty(node->lc);
node_empty(node->rc);
}
else if (is_full(node)) {
node_fill(node->lc);
node_fill(node->rc);
}
}
void inherit(TreeNode *node) { //标记上传+合并
if (is_full(node->lc) && is_full(node->rc)) {
node_fill(node);
return;
}
if (is_empty(node->lc) && is_empty(node->rc)) {
node_empty(node);
return;
}
node->lmax = is_empty(node->lc) ?
node->lc->size + node->rc->lmax :
node->lc->lmax;
node->rmax = is_empty(node->rc) ?
node->rc->size + node->lc->rmax :
node->rc->rmax;
node->cmax = max(node->lc->cmax, node->rc->cmax,
node->lc->rmax + node->rc->lmax);
}
int query(TreeNode *node) {
propagate(node);
if (node->lc->cmax >= d)
return query(node->lc);
if (node->lc->rmax + node->rc->lmax >= d)
return node->lc->rb - node->lc->rmax + 1;
if (node->rc->cmax >= d)
return query(node->rc);
return 0;
}
void checkin(TreeNode *node) {
if (node->rb < x || d < node->lb)
return;
if (x <= node->lb && node->rb <= d) {
node_fill(node);
return;
}
propagate(node);
checkin(node->lc);
checkin(node->rc);
inherit(node);
}
void checkout(TreeNode *node) {
if (node->rb < x || d < node->lb)
return;
if (x <= node->lb && node->rb <= d) {
node_empty(node);
return;
}
propagate(node);
checkout(node->lc);
checkout(node->rc);
inherit(node);
}
int main() {
int N = readint();
TreeNode *root = build_tree(1, N);
int M = readint();
while (M--)
if (readint() == 1) {
d = readint();
x = query(root);
printf("%d\n", x);
if (x) {
d += x - 1;
checkin(root);
}
}
else {
x = readint(); d = x + readint() - 1;
checkout(root);
}
return 0;
}