PKU 3667

Hotel

题型:线段树(设计并维护复杂域)

描述:旅店登记,1.找一段最靠前的连续w个空房间;2.退订[x,x-d+1]段的房间。

思路:

1. 域的设计

struct Seg {

    int l, r;

    int lx, rx, mx;

    char cv;

};

lx :左端连续空房间数

rx: 右端连续空房间数

mx: 连续最大空房间数

cv : = 0,全空, = 1 全满, = -1 非空非满。

2. 域的维护

开房:先用find(w, 1); 找到位置 rom, 然后用 mody(rom, rom+w-1, 0, 1); 进行插入操作

退房:进行删除操作mody(x, x-d+1, 1, 1)

因为此题区间的修改(插入和删除)很相似,所以用一个函数实现,0表示插入,1表示删除。

对cv域的维护包括   1. t[k].l == l && t[k].r == r 。 2. 根据父节点的cv值对子节点的修改(关键),find()和mody()中都需要有。代码:

 

 if (t[k].cv >= 0) {
t[k0].cv
= t[k0+1].cv = t[k].cv;
if (t[k].cv) p1 = p2 = 0;
else { p1 = t[k0].r-t[k0].l+1, p2 = t[k0+1].r-t[k0+1].l+1; }
t[k0].mx
= t[k0].lx = t[k0].rx = p1;
t[k0
+1].mx = t[k0+1].lx = t[k0+1].rx = p2;
t[k].cv
= -1;
}

 

 

 

lx, rx, mx需要在回溯的过程维护:mx 为 两个子节点的mx和交叉区间和的最大值,

父节点的lx = 左子节点的lx + (右子节点的lx);

父节点的rx = 右子节点的rx + (左子节点的rx);

当左右子节点的lx,rx为整个区间长时,()需加上。

 

t[k].mx = MAX(t[k0].mx, MAX(t[k0+1].mx, t[k0].rx+t[k0+1].lx));
t[k].lx
= t[k0].lx;
t[k].rx
= t[k0+1].rx;
if (t[k0].lx == t[k0].r-t[k0].l+1) t[k].lx += t[k0+1].lx;
if (t[k0+1].rx == t[k0+1].r-t[k0+1].l+1) t[k].rx += t[k0].rx;

 

 

代码
//3236K 610MS
#include <stdio.h>
#include
<string.h>
#define MIN(x,y) ((x)<(y)?(x):(y))
#define MAX(x,y) ((x)>(y)?(x):(y))
#define NL 65536

struct Seg {
int l, r;
int lx, rx, mx;//左端连续空房数,右端连续空房数,最大连续空房数
char cv; //1 满 0 空 -1 非空非满
}t[NL*2];
int rom;

void build(int l, int r, int k)
{
t[k].l
= l;
t[k].r
= r;
t[k].lx
= t[k].rx = t[k].mx = r-l+1;
t[k].cv
= 0;

int md = (l+r)>>1, k0 = k<<1;
if (l < r) {
build(l, md, k0);
build(md
+1, r, k0+1);
}
}

//flg == 0 插入,flg == 1 删除
void mody(int l, int r, bool flg, int k)
{
if (t[k].l == l && t[k].r == r) {
if (flg) {
t[k].lx
= t[k].rx = t[k].mx = t[k].r-t[k].l+1;
}
else {
t[k].lx
= t[k].rx = t[k].mx = 0;
}
t[k].cv
= flg^1;
return;
}

int md = (t[k].l+t[k].r)>>1, k0 = k<<1, p1, p2;
if (t[k].cv >= 0) {
t[k0].cv
= t[k0+1].cv = t[k].cv;
if (t[k].cv) p1 = p2 = 0;
else { p1 = t[k0].r-t[k0].l+1, p2 = t[k0+1].r-t[k0+1].l+1; }
t[k0].mx
= t[k0].lx = t[k0].rx = p1;
t[k0
+1].mx = t[k0+1].lx = t[k0+1].rx = p2;
t[k].cv
= -1;
}
if (r <= md)
mody(l, r, flg, k0);
else if (l > md)
mody(l, r, flg, k0
+1);
else {
mody(l, md, flg, k0);
mody(md
+1, r, flg, k0+1);
}
t[k].mx
= MAX(t[k0].mx, MAX(t[k0+1].mx, t[k0].rx+t[k0+1].lx));
t[k].lx
= t[k0].lx;
t[k].rx
= t[k0+1].rx;
if (t[k0].lx == t[k0].r-t[k0].l+1) t[k].lx += t[k0+1].lx;
if (t[k0+1].rx == t[k0+1].r-t[k0+1].l+1) t[k].rx += t[k0].rx;
}

void find(int w, int k)
{
if (t[k].l == t[k].r) {
rom
= t[k].l;
return;
}
int md = (t[k].l+t[k].r)>>1, k0 = k<<1, p1, p2;
if (t[k].cv >= 0) {
t[k0].cv
= t[k0+1].cv = t[k].cv;
if (t[k].cv) p1 = p2 = 0;
else { p1 = t[k0].r-t[k0].l+1, p2 = t[k0+1].r-t[k0+1].l+1; }
t[k0].mx
= t[k0].lx = t[k0].rx = p1;
t[k0
+1].mx = t[k0+1].lx = t[k0+1].rx = p2;
t[k].cv
= -1;
}
if (t[k0].mx >= w)
find(w, k0);
else if (t[k0].rx+t[k0+1].lx >= w)
rom
= t[k0].r-t[k0].rx+1;
else if (t[k0+1].mx >= w)
find(w, k0
+1);
}

int main()
{
int n, m;
int c, x, d;
// freopen("hotel2.in", "r", stdin);
while (scanf("%d%d", &n, &m) != EOF) {
build(
1, n, 1);
while (m--) {
scanf(
"%d", &c);
if (c == 1) {
scanf(
"%d", &d);
rom
= 0;
find(d,
1);
printf(
"%d\n", rom);
if (rom) {
mody(rom, rom
+d-1, 0, 1);
}
}
else {
scanf(
"%d%d", &x, &d);
mody(x, x
+d-1, 1, 1);
}
}
}
return 0;
}

 

 

一组数据

思路参考:北邮人

代码参考:傻崽NOCOW

posted @ 2010-07-18 16:00  superbin  阅读(699)  评论(1编辑  收藏  举报