//线段树 //对每个区间记录左连续数,右连续数,和最大连续 //最大连续用于判断是否存在满足条件的区间 //左右连续用来更新父区间的最大连续,注意两个区间的合并 //A完这一题,对线段树的回溯更新有了更深刻地体会 //对于线段树的更新,只需更新到所求的区间即可,而无需理会该区间的子区间 //若继续处理满足条件的子区间,就会让线段树退化到O(n),为了实现O(lgN)的插入和删除,就需要对区间进行标记 //当下次搜索时经过这个标记,再对子树进行处理,就可以了,这就是线段树快的原因 #include<iostream> #define MAX 50010 using namespace std; struct seg { int l,r,lSeries,rSeries,maxSeries;//记录区间的左连续,右连续,最大连续数 int cover;//cover标记区间覆盖情况,0表示可以住人,1表示住满人 }segTree[4 * MAX]; int L,R; void update(int fa)//回溯过程更新区间情况 { if(segTree[2*fa].cover != segTree[2*fa+1].cover) segTree[fa].cover = -1;//更新覆盖情况 else segTree[fa].cover = segTree[2*fa].cover; segTree[fa].lSeries = segTree[2*fa].lSeries; if(segTree[2*fa].cover == 0)//特殊情况,如果左子树是完全没人住,那么要补上右子树的作连续数 segTree[fa].lSeries += segTree[2*fa+1].lSeries; segTree[fa].rSeries = segTree[2*fa+1].rSeries; if(segTree[2*fa+1].cover == 0)//同上 segTree[fa].rSeries += segTree[2*fa].rSeries; segTree[fa].maxSeries = max(segTree[2*fa].rSeries + segTree[2*fa+1].lSeries,max(segTree[2*fa].maxSeries,segTree[2*fa+1].maxSeries));//更新最大连续数 } void renew(int fa)//根据当前区间的标记对左右子树进行更新,使得回溯更新一致 { if(segTree[fa].l == segTree[fa].r) return;//如果是叶子节点,则无需更新子树覆盖情况 if(segTree[fa].cover == 0) { segTree[2*fa].cover = segTree[2*fa+1].cover = 0; segTree[2*fa].lSeries = segTree[2*fa].rSeries = segTree[2*fa].maxSeries = segTree[2*fa].r - segTree[2*fa].l + 1; segTree[2*fa+1].lSeries = segTree[2*fa+1].rSeries = segTree[2*fa+1].maxSeries = segTree[2*fa+1].r - segTree[2*fa+1].l + 1; } else if(segTree[fa].cover == 1) { segTree[2*fa].cover = segTree[2*fa+1].cover = 1; segTree[2*fa].lSeries = segTree[2*fa].rSeries = segTree[2*fa].maxSeries = 0; segTree[2*fa+1].lSeries = segTree[2*fa+1].rSeries = segTree[2*fa+1].maxSeries = 0; } } void buildTree(int fa,int l,int r) { segTree[fa].l = l; segTree[fa].r = r; segTree[fa].lSeries = segTree[fa].rSeries = segTree[fa].maxSeries = r - l + 1; segTree[fa].cover = 0; if(l == r) return; int mid = (segTree[fa].l + segTree[fa].r) >> 1; if(r <= mid) buildTree(2*fa,l,r); else if(l > mid) buildTree(2*fa+1,l,r); else { buildTree(2*fa,l,mid); buildTree(2*fa+1,mid+1,r); } } void search(int fa,int series)//搜索符合条件的房间区间[L,R] { if(segTree[fa].maxSeries < series) return; if(segTree[fa].lSeries >= series) { L = segTree[fa].l; R = L + series - 1; return; } else if(segTree[2*fa].maxSeries >= series) search(2*fa,series); else if(segTree[2*fa].rSeries + segTree[2*fa+1].lSeries >= series) { L = segTree[2*fa].r - segTree[2*fa].rSeries + 1; R = L + series - 1; return; } else search(2*fa+1,series); } void Fill(int fa,int l,int r) { renew(fa);//根据当前区间处理子树 if(segTree[fa].l == l && segTree[fa].r == r) { segTree[fa].lSeries = segTree[fa].rSeries = segTree[fa].maxSeries = 0; segTree[fa].cover = 1; return; } int mid = (segTree[fa].l + segTree[fa].r) >> 1; if(r <= mid) Fill(2*fa,l,r); else if(l > mid) Fill(2*fa+1,l,r); else { Fill(2*fa,l,mid); Fill(2*fa+1,mid+1,r); } update(fa);//回溯更新 } void Empty(int fa,int l,int r) { renew(fa); if(segTree[fa].l == l && segTree[fa].r == r) { segTree[fa].lSeries = segTree[fa].rSeries = segTree[fa].maxSeries = segTree[fa].r - segTree[fa].l + 1; segTree[fa].cover = 0; return; } int mid = (segTree[fa].l + segTree[fa].r) >> 1; if(r <= mid) Empty(2*fa,l,r); else if(l > mid) Empty(2*fa+1,l,r); else { Empty(2*fa,l,mid); Empty(2*fa+1,mid+1,r); } update(fa); } int main() { //freopen("in.txt","r",stdin); int n,q,series,type,st,num; scanf("%d%d",&n,&q); buildTree(1,1,n); while(q--) { scanf("%d",&type); if(type == 1) { L = 0; scanf("%d",&series); search(1,series); printf("%d/n",L); if(L != 0) Fill(1,L,R); } else { scanf("%d%d",&st,&num); Empty(1,st,st + num - 1); } } return 0; }