题意:
去掉题目背景,就是给你一个[1,n]的区间,初始时,整个区间为空,在区间进行俩个操作:
1) 输入 1 D :在区间上从左到右找出第一个连续的长度为D 的空间,并将该区间填满,输出区间的端点,若不存在,输出0
2) 输入 2 a b: 将区间[a,a+b-1] 填满
分析:很明显是用线段树进行维护,关键是每一个节点需要保存该区间的些什么值?
这里我们可以想到,因为要找出的是一个连续的空区间的左端点,这个区间可能分布在左儿子上,右儿子上,或者可能在俩边都有,这样给查询带来了极大的不方便。不过,我们可以充分利用线段树的结构特点,通过保存与区间左右端点有关的信息,就可以遍历整个区间的信息。
我们给每一个节点添加四个域,一个保存该区间是否整个被填满,一个域保存该区间存在的最大的连续的区间长度,一个域保存该区间以左端点开始的空区间的长度,一个域保存该区间以右端点结束的空区间的长度;
这样,我们通过维护线段树每一个域的值,就可以得到整个区间内每一个连续的空区间的长度;
维护过程头脑要异常的清醒啊!!!!
#include<iostream> #include<algorithm> #define MAXN 50005 using namespace std; struct node { int ls,rs,ms,c; }p[MAXN<<2]; void PushDown(int k,int m) { int kl=k<<1,kr=kl+1; if(p[k].c!=-1) { p[kl].c=p[kr].c=p[k].c; p[kl].ls=p[kl].rs=p[kl].ms= p[k].c? 0: m- (m>>1); p[kr].ls=p[kr].rs=p[kr].ms= p[k].c? 0: (m>>1); p[k].c=-1; } } void PushUp(int k,int m)//除了查询之外,难点就在于这一步维护了,将子区间的信息传递给回来 { int kl=k<<1,kr=kl+1; p[k].ls=p[kl].ls; p[k].rs=p[kr].rs; if(p[kl].ls== m-(m>>1))//若左儿子整个为空区间,则可以将右儿子的左连续空间长度加到整个空间的左连续空间长度 p[k].ls+=p[kr].ls; if(p[kr].rs== m>>1) p[k].rs+=p[kl].rs; p[k].ms=max(p[kl].rs+p[kr].ls,max(p[kl].ms,p[kr].ms));//整个区间存在的最长的空区间长度等于 左连续区间,右连续区间,或中间存在的最大长度的空区间中的最大值 } void build(int k,int s,int t)//建树 { p[k].ls=p[k].rs=p[k].ms=t-s+1; p[k].c=-1; if(s==t) return ; int kl=k<<1,kr=kl+1,mid=(s+t)>>1; build(kl,s,mid); build(kr,mid+1,t); } void update(int k,int c,int s,int t,int l,int r)//根据c的值,将区间[l,r]填满或清空 { if(l<=s && t<=r) { p[k].c=c; p[k].ms=p[k].ls=p[k].rs=c? 0: t-s+1; return ; } int kl=k<<1,kr=kl+1,mid=(s+t)>>1; PushDown(k,t-s+1); if(l<=mid) update(kl,c,s,mid,l,r); if(r>mid) update(kr,c,mid+1,t,l,r); PushUp(k,t-s+1); } int query(int k,int w,int s,int t) { if(s==t) return s; PushDown(k,t-s+1); int kl=k<<1,kr=kl+1,mid=(s+t)>>1; if(p[kl].ms>=w) //左区间本身存在着长度大于w的空区间 return query(kl,w,s,mid); else if(p[kl].rs+p[kr].ls>=w) //保存左右端点空区间长度的目的就在于此了,p[kl].rs+p[kr].ls 是区间内与中点有关的连续的空区间的长度 return mid-p[kl].rs+1; return query(kr,w,mid+1,t); } int main() { int n,m; int a,b,c; scanf("%d %d",&n,&m); build(1,1,n); while(m--) { scanf("%d",&c); if(c==1) { scanf("%d",&a); if(p[1].ms<a)//整个区间内的最大长度的空区间小于a puts("0"); else { b=query(1,a,1,n); printf("%d\n",b); update(1,1,1,n,b,b+a-1); } } else { scanf("%d %d",&a,&b); update(1,0,1,n,a,a+b-1); } } return 0; }