POJ [3667] Hotel 【Line segment tree interval merge + delay mark】

Description


The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as their vacation residence. This immense hotel has N (1 ≤ N ≤ 50,000) rooms all located on the same side of an extremely long hallway (all the better to see the lake, of course).The cows and other visitors arrive in groups of size Di (1 ≤ Di ≤ N) and approach the front desk to check in. Each group i requests a set of Di contiguous rooms from Canmuu, the moose staffing the counter. He assigns them some set of consecutive room numbers r..r+Di-1 if they are available or, if no contiguous set of rooms is available, politely suggests alternate lodging. Canmuu always chooses the value of r to be the smallest possible.Visitors also depart the hotel from groups of contiguous rooms. Checkout i has the parameters Xi and Di which specify the vacating of rooms Xi ..Xi +Di-1 (1 ≤ Xi ≤ N-Di+1). Some (or all) of those rooms might be empty before the checkout.Your job is to assist Canmuu by processing M (1 ≤ M < 50,000) checkin/checkout requests. The hotel is initially unoccupied.

Input

* Line 1: Two space-separated integers: N and M
* Lines 2..M+1: Line i+1 contains request expressed as one of two possible formats: (a) Two space separated integers representing a check-in request: 1 and Di (b) Three space-separated integers representing a check-out: 2, Xi, and Di 

Output

* Lines 1.....: For each check-in request, output a single line with a single integer r, the first room in the contiguous sequence of rooms to be occupied. If the request cannot be satisfied, output 0.

Sample Input

10 6
1 3
1 3
1 3
1 3
2 5 5
1 6

Sample Output

1
4
7
0
5

The main idea:
There is a hotel with N rooms, which is completely empty at first. There are M operations afterwards. The operations include two types: enter 1 D, which means that you want to move into D, and the room number assigned to the request is continuous. If there are empty continuous rooms, output the smallest room number that meets the conditions, otherwise output 0 (that is, there are no continuous D rooms); enter 2 XD, indicating that the room number is X ... X + D + 1 and everyone leaves .

Analysis: The
topic involves interval operations, consider using a line segment tree to build a model. The nodes of the line segment tree use sum to maintain the length of the largest continuous idle interval in the interval, lsum maintains the interval [l, r] from l to the length of the continuous idle interval to the right, rsum maintains the interval [l, r] from r The length of the continuous free interval to the left (easy to maintain the interval spanning the node interval). Use delay markers to reduce update depth. When the guest leaves, merge the free zone upwards.

See the code for specific explanation.

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <cstdio> 
#include <map> 
#include <iomanip>

#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define INF 0x3f3f3f3f

using namespace std;

struct segtree{
	int l,r;
	int lsum,rsum,sum;//lsum从左端开始连续的区间长度,rsum从右端开始连续的区间长度 
	int tag;//延迟标记 
};

segtree t[50005*4];

void build(int p,int l,int r){//建树 
	int mid=(l+r)/2;
	t[p].l=l;
	t[p].r=r;
	t[p].lsum=t[p].rsum=t[p].sum=r-l+1;
	t[p].tag=-1;
	if(l==r)  return;
	build(p*2,l,mid);
	build(2*p+1,mid+1,r);
}

void pushdown(int p){//将父节点的状态向下传递(延迟标记的传递) 
	if(t[p].tag!=-1){//说明父节点的状态已被改变 
		int lson=p*2,rson=p*2+1;
		t[lson].tag=t[rson].tag=t[p].tag;
		if(t[p].tag==1){//父节点的区间被占用 
			t[lson].lsum=t[lson].rsum=t[lson].sum=0;
			t[rson].lsum=t[rson].rsum=t[rson].sum=0;
		}
		else{//父节点的区间空闲 
			t[lson].lsum=t[lson].rsum=t[lson].sum=(t[lson].r-t[lson].l+1);
			t[rson].lsum=t[rson].rsum=t[rson].sum=(t[rson].r-t[rson].l+1);
		}
		t[p].tag=-1;//父节点传递完成后标志复原 
	}
}

int query(int len,int p){
	if(t[p].l==t[p].r){
		return t[p].l;
	}
	pushdown(p);//首先将本节点的状态传递下去,便于接下来的递归查询 
	int lson=p*2;
	int rson=p*2+1;
	if(t[lson].sum>=len){//如果左侧的空闲长度足够,先检测左侧(保证最小的编号) 
		return query(len,lson);
	}
	else if(t[lson].rsum+t[rson].lsum>=len){//考虑跨越左右两侧的区间 
		return (t[p].l+t[p].r)/2-t[lson].rsum+1;
	} 
	else{//检测右侧 
		return query(len,rson);
	} 
} 

void pushup(int p){//区间合并 
	int lson=p*2,rson=p*2+1;
	t[p].lsum=t[lson].lsum;
	t[p].rsum=t[rson].rsum;
	//进一步更新lsum和rsum 
	if(t[lson].lsum==(t[lson].r-t[lson].l+1))  t[p].lsum+=t[rson].lsum;
	if(t[rson].rsum==(t[rson].r-t[rson].l+1))  t[p].rsum+=t[lson].rsum;
	//sum取三种情况下的最大值 
	t[p].sum=max(t[lson].rsum+t[rson].lsum,max(t[lson].sum,t[rson].sum));
}

void update(int p,int L,int R,int flag){//flag=1表示占用,flag=0表示空闲 
	int lson=p*2,rson=p*2+1;
	if(L<=t[p].l&&R>=t[p].r){//区间被完全覆盖 
		t[p].tag=flag;
		t[p].lsum=t[p].rsum=t[p].sum=(flag?0:(t[p].r-t[p].l+1));
		return;//由于此处直接返回,所以需要延迟标记,此处未更新该节点的子树 
	}
	pushdown(p);//进入子节点前先传递延迟标记,便于接下来的递归更新 
	int mid=(t[p].l+t[p].r)/2;
	if(L<=mid){
		update(lson,L,R,flag);
	} 
	if(R>mid){
		update(rson,L,R,flag);
	}
	pushup(p);//子节点更新返回后要更新父节点 
}



int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	build(1,1,n);
	rep(i,1,m){
		int com;
		scanf("%d",&com);
		if(com==1){
			int d;
			scanf("%d",&d);
			if(d>t[1].sum)  printf("0\n");//如果需要入住的量大于整个区间内的连续空闲区间,则无法安排 
			else{
				int ans=query(d,1);
				printf("%d\n",ans);
				update(1,ans,ans+d-1,1);//记得要更新 
			}
		}
		else{
			int x,d;
			scanf("%d%d",&x,&d); 
			update(1,x,x+d-1,0);
		}
	} 
	return 0;
}

 

 

 

Published 30 original articles · won 5 · 900 views

Guess you like

Origin blog.csdn.net/qq_42840665/article/details/96893844