POJ 3667 Hotel
线段树
题意
设计数据结构,维护一段序列,初始全1,支持2种操作:
- 将一段区间置1
- 从头查找第一段长度不小于k的序列,并将这k个位置置0
思路
线段树维护序列。维护前缀1(pre),后缀1(suf),区间最大连续1(sum)。更新时取左右中长度大的更新。
找不小于k时有坑,必须按照下面步骤一步步来:
- 如果跟节点的区间最大连续1小于k,那么无解
- 如果左子区间sum大于等于k,递归左子区间
- 如果左子区间suf+右子区间pre大于等于k,输出
mid-stree[rt<<1].suf+1
!!这一步不能用当前区间sum和lpos rpos代替,因为最大sum有可能出现在右子区间。 - 递归右子区间
别忘了递归基,l==r时返回l。我在这wa了好久。
代码
感觉挺考验编程能力的
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=100007;
const int oo=0x3f3f3f3f;
struct Stree
{
int sum;int pre, suf;int set1;int set0;
//int lpos, rpos;
}stree[MAXN<<2];
int max3(int a, int b, int c) { return std::max(std::max(a, b), c); }
void pushup(int l, int r, int rt)
{
int ll=stree[rt<<1].sum, rr=stree[rt<<1|1].sum, mm=stree[rt<<1].suf+stree[rt<<1|1].pre;
if(ll>=rr&&ll>=mm)
stree[rt].sum=ll;
else if(rr>ll&&rr>mm)
stree[rt].sum=rr;
else
stree[rt].sum=mm;
int mid=(l+r)>>1;
if(stree[rt<<1].pre==mid-l+1)
stree[rt].pre=stree[rt<<1].pre+stree[rt<<1|1].pre;
else stree[rt].pre=stree[rt<<1].pre;
if(stree[rt<<1|1].suf==r-mid)
stree[rt].suf=stree[rt<<1].suf+stree[rt<<1|1].suf;
else stree[rt].suf=stree[rt<<1|1].suf;
}
void pushdown(int l, int r, int rt)
{
int mid=(l+r)>>1;
if(stree[rt].set0)
{
stree[rt<<1].set0=stree[rt<<1|1].set0=1;
stree[rt<<1].set1=stree[rt<<1|1].set1=0;
stree[rt<<1].sum=stree[rt<<1].pre=stree[rt<<1].suf=0;
stree[rt<<1|1].sum=stree[rt<<1|1].pre=stree[rt<<1|1].suf=0;
stree[rt].set0=0;
}
if(stree[rt].set1)
{
stree[rt<<1].set0=stree[rt<<1|1].set0=0;
stree[rt<<1].set1=stree[rt<<1|1].set1=1;
stree[rt<<1].sum=stree[rt<<1].pre=stree[rt<<1].suf=mid-l+1;
stree[rt<<1|1].sum=stree[rt<<1|1].pre=stree[rt<<1|1].suf=r-mid;
stree[rt].set1=0;
}
}
void build(int l, int r, int rt)
{
stree[rt].pre=stree[rt].set1=stree[rt].suf=stree[rt].sum=0;
if(l==r) { stree[rt].pre=stree[rt].suf=stree[rt].sum=1; return; }
int mid=(l+r)>>1;
build(lson), build(rson);
pushup(l, r, rt);
}
void update(int L, int R, int v, int l, int r, int rt)
{
if(L<=l&&r<=R)
{
if(v==1)
{
stree[rt].set1=1;stree[rt].sum=r-l+1;stree[rt].set0=0;
stree[rt].pre=stree[rt].suf=r-l+1;
}
else
{
stree[rt].set0=1;stree[rt].sum=0;stree[rt].set1=0;
stree[rt].pre=stree[rt].suf=0;
}
return;
}
pushdown(l, r, rt);
int mid=(l+r)>>1;
if(L<=mid) update(L, R, v, lson);
if(R>mid) update(L, R, v, rson);
pushup(l, r, rt);
}
int query(int am, int l, int r, int rt)
{
if(l==r) return l;
pushdown(l, r, rt);
int mid=(l+r)>>1;
if(am<=stree[rt<<1].sum)
return query(am, lson);
else if(am<=stree[rt<<1].suf+stree[rt<<1|1].pre)
return mid-stree[rt<<1].suf+1;
else if(am<=stree[rt<<1|1].sum)
return query(am, rson);
}
int main()
{
int n, m;
while(scanf("%d%d", &n, &m)==2)
{
build(1, n, 1);
for(int i=0;i<m;i++)
{
int op;scanf("%d", &op);
if(op==1)
{
int len;scanf("%d", &len);int res=0;
if(stree[1].sum<len) res=0;
else
{
res=query(len, 1, n, 1);
update(res, res+len-1, 0, 1, n, 1);
}
printf("%d\n", res);
}
else if(op==2)
{
int x, y;scanf("%d%d", &x, &y);
update(x, x+y-1, 1, 1, n, 1);
}
}
}
//system("pause");
return 0;
}