链接:http://poj.org/problem?id=3667
题意:n个连续的房间m个操作。操作分两种,第一种以1 x形式给出,找到最左的能连续容下x个人的连续房间,并输出左端点的编号,如果找不到就输出0.第二种以2 l x的形式给出,表示以l为起点的x个房间都清空。
查询的时候要能直接获取区间的最大连续空房间,这样就能判断能不能连续放下这x个人,但这样还确定不了具体放哪。放的位置有三种情况1.放在左儿子那个区间。2.放在右儿子那个区间。3.放在左右儿子中间,就是占用左区间的右部分和右区间的左部分。
这样就需要用sum保存整个区间最大的连续段,lsum保存从左端开始的最大连续段,rsum保存右端开始的最大连续段
用一个标记mark表示区间状态,0:区间全空。1:区间全满。-1:当前区间已初始化,不用向下更新
向下更新策略:先向下转移标记mark,在通过标记更新相应的数据。
向上更新策略:sum=max(左儿子的sum,右儿子的sum,左右儿子中间部分)
lsum=左儿子的lsum,如果左儿子为空还要加上右儿子的lsum
rsum=右儿子的rsum,如果右儿子为空还要加上左儿子的rsum
#include
#include
#define MAXN 50005
struct node
{
int l,r;
int mark;
int lsum,rsum,sum;
int getlen() {return r-l+1;}
void getsum() {lsum=rsum=sum=(mark?0:getlen());}
}t[MAXN*4];
int max(int a,int b) {return a>b?a:b;}
void construct(int l,int r,int p)
{
t[p].l=l,t[p].r=r;
t[p].lsum=t[p].rsum=t[p].sum=t[p].getlen();
t[p].mark=-1;
if(l==r) return ;
int m=(l+r)>>1;
construct(l,m,p*2);
construct(m+1,r,p*2+1);
}
int query(int x,int p)
{
if(t[p].l==t[p].r&&x==1) return t[p].l;//单个节点特判
if(t[p].mark!=-1)
{
t[p*2].mark=t[p*2+1].mark=t[p].mark;
t[p].mark=-1;
t[p*2].getsum();
t[p*2+1].getsum();
}
if(x<=t[p*2].sum) return query(x,p*2);
else if(t[p*2].rsum+t[p*2+1].lsum>=x) return t[p*2].r-t[p*2].rsum+1;
else if(x<=t[p*2+1].sum) return query(x,p*2+1);
else return 0;
}
void modify(int l,int r,int val,int p)
{
if(t[p].l==l&&t[p].r==r)
{
t[p].mark=val;
t[p].getsum();
return ;
}
if(t[p].mark!=-1)
{
t[p*2].mark=t[p*2+1].mark=t[p].mark;
t[p].mark=-1;
//每次更新了mark标记都要重新获取长度
t[p*2].getsum();
t[p*2+1].getsum();
}
int m=(t[p].l+t[p].r)>>1;
if(r<=m) modify(l,r,val,p*2);
else if(l>m) modify(l,r,val,p*2+1);
else {modify(l,m,val,p*2);modify(m+1,r,val,p*2+1);}
int temp=max(t[p*2].sum,t[p*2+1].sum);
t[p].sum=max(temp,t[p*2].rsum+t[p*2+1].lsum);
t[p].lsum=t[p*2].lsum;
t[p].rsum=t[p*2+1].rsum;
if(t[p*2].sum==t[p*2].getlen()) t[p].lsum+=t[p*2+1].lsum;
if(t[p*2+1].sum==t[p*2+1].getlen()) t[p].rsum+=t[p*2].rsum;
}
int main()
{
int op,l,x,n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
construct(1,n,1);
while(m--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d",&x);
int flag=query(x,1);
printf("%d\n",flag);
if(flag) modify(flag,flag+x-1,1,1);
}
else
{
scanf("%d%d",&l,&x);
modify(l,l+x-1,0,1);
}
}
}
return 0;
}