1 /* 2 Name: 3 Copyright: 4 Author: 5 Date: 28/04/13 21:55 6 Description: 7 刚开始做这道题的时候,第一感觉用线段树应该很容易实现,结果发现我没做过此类的线段树题目 8 然后上网看了别人的代码,才了有点思路,现总结如下: 9 这道题题意就是旅馆订房问题,由于牵扯到某一段区间的查找与运算,所以选择了线段树求解, 10 用free表示此段区间房间是否可用,lmax代表这段区间从左边起最长空闲房间数,rmax表示这段区间 11 从右边起最长空闲房间数,tmax表示整个区间上的最长连续空闲房间数,查找连续空房间数时,过程如下: 12 1、如果1~n区间的tmax值都比待查长度len小,就无解,否则有解执行2 13 2、假如区间lmax是否大于等于len,直接返回l ,否则执行3 14 3、对于每一个区间,如果它的左儿子的tmax值大于等于len,到左儿子里去找。否则执行4 15 4、如果左儿子的rmax加上有儿子的lmax大于等于len,直接返回左儿子的右端点减去左儿子的rmax值。 16 5、否则到右儿子里去找。 17 PS:对于上述过程,如果满足前面的条件,则不再考虑后面的情况。 18 更新的时候既进行下压操作,在对某段区间进行处理后(清空房间或占用房间)后,进行更新父节点, 19 细节看注释!! 20 */ 21 #include<iostream> 22 #include<cstdio> 23 const int N=50010; 24 using namespace std; 25 struct Node{ 26 int l,r; 27 int free; 28 int lmax,rmax,tmax; 29 }tree[3*N]; 30 int build(int l,int r,int i){ 31 tree[i].l=l; 32 tree[i].r=r; 33 tree[i].lmax=tree[i].rmax=tree[i].tmax=r-l+1; //初始化为区间大小 34 tree[i].free=0; 35 if(l<r){ 36 int mid=(l+r)>>1; 37 build(l,mid,i<<1); 38 build(mid+1,r,i<<1|1); 39 } 40 } 41 int query(int i,int len){ 42 if(tree[i].tmax<len) return 0; //情况1 43 if(tree[i].lmax>=len) return tree[i].l; //情况2 44 if(tree[i<<1].tmax>=len) return query(i<<1,len); //情况3 45 else if(tree[i<<1].rmax+tree[i<<1|1].lmax >= len) //情况4 46 return tree[i<<1].r-tree[i<<1].rmax+1; 47 else return query(i<<1|1,len); //情况5 48 } 49 int update(int l,int r,int i,int state){ 50 if(tree[i].l==l&&tree[i].r==r){ //找到此段区间 51 tree[i].free=state; 52 if(state){ //若为1则占用房间 ,否则腾出房间 53 tree[i].lmax=tree[i].rmax=tree[i].tmax=0; 54 }else{ 55 tree[i].lmax=tree[i].rmax=tree[i].tmax=tree[i].r-tree[i].l+1; 56 } 57 }else if(tree[i].r > tree[i].l){ 58 if(tree[i].free==1){ //树节点的相应信息向下压,即节点信息细致化 59 tree[i<<1].free=tree[i<<1|1].free=1; 60 tree[i<<1].lmax=tree[i<<1].rmax=tree[i<<1].tmax=0; 61 tree[i<<1|1].lmax=tree[i<<1|1].rmax=tree[i<<1|1].tmax=0; 62 } 63 if(tree[i].free==0){ 64 tree[i<<1].free=tree[i<<1|1].free=0; 65 tree[i<<1].lmax=tree[i<<1].rmax=tree[i<<1].tmax=tree[i<<1].r-tree[i<<1].l+1; 66 tree[i<<1|1].lmax=tree[i<<1|1].rmax=tree[i<<1|1].tmax=tree[i<<1|1].r-tree[i<<1|1].l+1; 67 } 68 int mid=(tree[i].r+tree[i].l)>>1; 69 if(mid>=r) update(l,r,i<<1,state); 70 else if(mid<l) update(l,r,i<<1|1,state); 71 else{ 72 update(l,mid,i<<1,state); 73 update(mid+1,r,i<<1|1,state); 74 } 75 tree[i].lmax=tree[i<<1].lmax; //树节点相应信息向上推送,即更新父节点信息 76 tree[i].rmax=tree[i<<1|1].rmax; 77 if(tree[i<<1].free==0) tree[i].lmax+=tree[i<<1|1].lmax; 78 if(tree[i<<1|1].free==0) tree[i].rmax+=tree[i<<1].rmax; 79 tree[i].tmax=max(tree[i<<1].tmax,tree[i<<1|1].tmax); //选取左孩子tmax和右孩子tmax及左右之间结合的最大值 80 tree[i].tmax=max(tree[i].tmax,tree[i<<1].rmax+tree[i<<1|1].lmax); 81 if(tree[i<<1].free==tree[i<<1|1].free) //更新父节点的使用情况 82 tree[i].free=tree[i<<1].free; 83 else tree[i].free=-1; 84 } 85 } 86 int main() 87 { 88 int N,M,s,num,start,flag; 89 while(~scanf("%d%d",&N,&M)){ 90 build(1,N,1); 91 while(M--){ 92 scanf("%d",&flag); 93 if(flag==1){ 94 scanf("%d",&s); 95 start=query(1,s); //start为0说明未找到符合房间 96 printf("%d\n",start); 97 if(start) update(start,start+s-1,1,1); //假如 start不为零,那么就需要占用 98 }else{ 99 scanf("%d%d",&s,&num); 100 update(s,s+num-1,1,0); 101 } 102 } 103 } 104 return 0; 105 }