题目链接:http://poj.org/problem?id=3667
题意:很多群人去住宾馆,他们想尽可能住在连在一起的房间,每次安排房间的时候,如果有连续足够多的房间,则从房间号最小的开始安排,输出这个房间号,如果没有连续的那么多的房间,那么输出0,而这些人分开住,但是也是尽可能连续,房间号尽可能小……然后有人离开宾馆,也是一个区间的人都离开……
终于做到了线段树区间合并系列,刚开始看了这个题完全不知道怎么做,也看了不少人的解题报告,没能明白,最后依然回归看notonlysuccess大神的源码,才有了感觉
首先设计状态
一个结构体里有四个属性
l表示该区间最左边连续的房间的数量,r表示最右边
max表示该区间内连续房间的最大数,cov表示该区间的入住情况,0表示没人住,1表示住满 ,-1表示子区间的信息已经被更新(防止重复更新子区间)如果是-1就不push_down
下面说说push_down和push_up这两个最关键的函数:
push_up就是根据两个子区间,算出当前区间的l,r,max,如果左儿子的l等于左儿子的长度,即左儿子全没人住,那么父亲的l就是左儿子的l加上右儿子的l,否则父亲的l就是左儿子的l…………父亲的r算法类似,那么父亲的max?可能是左儿子的max,右儿子的max,也可能是左儿子的r加上右儿子的l拼起来
void push_up(int l,int r,int rt)
{
p[rt].l = p[rt<<1].l;
p[rt].r = p[rt<<1|1].r;
int mid = r+l>>1;
if(p[rt].l==mid-l+1) p[rt].l+=p[rt<<1|1].l;
if(p[rt].r==r-mid) p[rt].r+=p[rt<<1].r;
p[rt].max = max(max(p[rt<<1].max,p[rt<<1|1].max),p[rt<<1].r+p[rt<<1|1].l);
}
push_down
如果当前节点的cov是-1则不进行
如果是0,那么就是说两个子区间都应该清空
如果是1,那么两个子区间都应该填满
更新完之后需要把cov置成-1
每次有人来住的时候得先判断人数和p[1].max,如果大于,说明没有连续的房间,输出0,否则,就query出最左边的房间号,然后根据这个房间号再来update一个区间
如果是有人离开宾馆,则直接update即可
具体的看函数就很明了
#include <cstdio>
#include <cstring>
const int MAX = 50010;
struct point
{
int l,r,max,cov;
}p[MAX<<2];
int max(int a,int b)
{
return (a>b)?a:b;
}
void push_up(int l,int r,int rt)
{
p[rt].l = p[rt<<1].l;
p[rt].r = p[rt<<1|1].r;
int mid = r+l>>1;
if(p[rt].l==mid-l+1) p[rt].l+=p[rt<<1|1].l;
if(p[rt].r==r-mid) p[rt].r+=p[rt<<1].r;
p[rt].max = max(max(p[rt<<1].max,p[rt<<1|1].max),p[rt<<1].r+p[rt<<1|1].l);
}
void push_down(int l,int r,int rt)
{
if(p[rt].cov!=-1)
{
p[rt<<1].cov = p[rt<<1|1].cov = p[rt].cov;
if(p[rt].cov)
p[rt<<1].l = p[rt<<1|1].l = p[rt<<1].r = p[rt<<1|1].r = p[rt<<1].max = p[rt<<1|1].max = 0;
else
{
int mid = r+l>>1;
p[rt<<1].l = p[rt<<1].r = p[rt<<1].max = mid-l+1;
p[rt<<1|1].l = p[rt<<1|1].r = p[rt<<1|1].max = r-mid;
}
p[rt].cov = -1;
}
}
void build(int l,int r,int rt)
{
p[rt].l = p[rt].r = p[rt].max = r-l+1;
p[rt].cov = -1;
if(l==r)
{
return;
}
int mid = r+l>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
}
void update(int a,int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
if(a)
p[rt].l = p[rt].r = p[rt].max = 0;
else
p[rt].l = p[rt].r = p[rt].max = r-l+1;
p[rt].cov = a;
return;
}
int mid = r+l>>1;
push_down(l,r,rt);
if(L<=mid) update(a,L,R,l,mid,rt<<1);
if(R>mid) update(a,L,R,mid+1,r,rt<<1|1);
push_up(l,r,rt);
}
int query(int a,int l,int r,int rt)
{
if(l==r)
{
return l;
}
int mid = r+l>>1;
push_down(l,r,rt);
if(p[rt<<1].max>=a) return query(a,l,mid,rt<<1);
if(p[rt<<1].r+p[rt<<1|1].l>=a) return mid-p[rt<<1].r+1;
return query(a,mid+1,r,rt<<1|1);
}
int main()
{
int n,m,k,x,y;
while(scanf("%d%d",&n,&m)==2)
{
build(1,n,1);
while(m--)
{
scanf("%d",&k);
if(k==1)
{
scanf("%d",&x);
if(p[1].max<x) puts("0");
else
{
int tmp = query(x,1,n,1);
printf("%d\n",tmp);
update(1,tmp,tmp+x-1,1,n,1);
}
}
else
{
scanf("%d%d",&x,&y);
update(0,x,x+y-1,1,n,1);
}
}
}
return 0;
}