POJ [3667]ホテル【線分ツリー間隔マージ+遅延マーク】

説明文


牛は北に向かってカナダのサンダーベイに向かい、文化的な豊かさを得て、日当たりの良いスペリオル湖の海岸で休暇を楽しみます。かつて有能な旅行代理店であったベシーは、有名なカンバーランドストリートにあるブルムースホテルを休暇用の邸宅として指定しました。この巨大なホテルには、N(1≤N≤50,000)の部屋がすべて非常に長い廊下の同じ側にあります(もちろん湖を見た方がいいです)。牛や他の訪問者は、サイズDi(1 ≤Di≤N)で、フロントデスクに近づいてチェックインします。各グループiは、カウンターにスタッフがいるムースであるCanmuuに、Di隣接する部屋のセットを要求します。利用可能な場合は、いくつかの連続した部屋番号r..r + Di-1のセットを割り当てます。また、隣接する部屋のセットがない場合は、代替の宿泊施設を丁寧に提案します。Canmuuは常に最小のrの値を選択します。訪問者はまた、隣接する部屋のグループからホテルを出発します。チェックアウトiには、部屋Xi ..Xi + Di-1(1≤Xi≤N-Di + 1)の空席を指定するパラメーターXiおよびDiがあります。これらの部屋の一部(またはすべて)は、チェックアウト前は空である可能性があります。あなたの仕事は、M(1≤M <50,000)チェックイン/チェックアウトリクエストを処理することによってCanmuuを支援することです。当ホテルは最初は空いています。

入力

*行1:スペースで区切られた2つの整数:NおよびM
*行2..M + 1:行i + 1には、次の2つの可能な形式のいずれかで表現された要求が含まれます:(a)チェックイン要求を表す2つのスペースで区切られた整数: 1およびDi(b)チェックアウトを表すスペースで区切られた3つの整数:2、Xi、およびDi 

出力

* Lines 1 .....:チェックインリクエストごとに、占有される部屋の連続するシーケンスの最初の部屋である単一の整数rを使用して、単一の行を出力します。要求を満たせない場合は、0を出力します。

入力例

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

出力例

1
4
7
0
5

主なアイデア:
最初は完全に空のN部屋のホテルがあります。その後の操作はMです。操作には2つのタイプがあります。1Dを入力することはDに移動することを意味し、リクエストに割り当てられた部屋番号は連続しています。空の連続する部屋がある場合は、条件を満たす最小の部屋番号を出力します。それ以外の場合は0を出力します(つまり、連続するD部屋はありません)。2XDを入力します。これは、部屋番号がX ... X + D + 1であり、全員が去る。

分析:
トピックにはインターバル操作が含まれます。ラインセグメントツリーを使用してモデルを構築することを検討してください。ラインセグメントツリーのノードは、合計を使用して、間隔内の最大の連続アイドル間隔の長さを維持します。lsumは、間隔[l、r]をlから維持し、連続アイドル間隔の右側までの長さを維持します。左側の連続するフリーインターバルの長さ(ノードインターバルにまたがるインターバルを維持しやすい)。遅延マーカーを使用して、更新の深さを減らします。ゲストが離れたら、フリーゾーンを上にマージします。

具体的な説明については、コードを参照してください。

#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;
}

 

 

 

公開された30元の記事 ウォンの賞賛5 ビュー900

おすすめ

転載: blog.csdn.net/qq_42840665/article/details/96893844