tozangezan's diary

勝手にソースコードをコピペして利用しないでください。

PKU 3667 Hotel

疲れる問題でした。

解法
「空所の左端の位置」「空所の右端の位置」「空所のサイズ(左端だけもっている)」を遅延更新するsegtreeで持つ。
WAの原因はホテルに人を入れるときの「空所の左端の位置」を人数分右にずらすのを忘れていたからでした。

#include<stdio.h>
#include<algorithm>
using namespace std;
int left[1<<17];
int l_t[1<<17];
int right[1<<17];
int r_t[1<<17];
int sz[1<<17];
int s_t[1<<17];
int find(int a){
	if(sz[1]<a)return -1;
	int L=0;
	int R=65535;
	int ind=1;
	while(L<R){
		if(s_t[ind]){
			s_t[ind]=0;
			s_t[ind*2]=s_t[ind*2+1]=1;
			sz[ind*2]=sz[ind*2+1]=sz[ind];
		}
		if(sz[ind*2]>=a){
			ind=ind*2;
			R=(L+R)/2;
		}else{
			ind=ind*2+1;
			L=(L+R)/2+1;
		}
	}
	return L;
}
void updateS(int a,int b,int c,int d,int e,int f){
	if(d<a||b<c)return;
	if(c<=a&&b<=d){
		s_t[e]=1;
		sz[e]=f;
		return;
	}
	if(s_t[e]){
		s_t[e]=0;
		s_t[e*2]=s_t[e*2+1]=1;
		sz[e*2]=sz[e*2+1]=sz[e];
	}
	updateS(a,(a+b)/2,c,d,e*2,f);
	updateS((a+b)/2+1,b,c,d,e*2+1,f);
	sz[e]=max(sz[e*2],sz[e*2+1]);
}
void updateL(int a,int b,int c,int d,int e,int f){
	if(d<a||b<c)return;
	if(c<=a&&b<=d){
		l_t[e]=1;
		left[e]=f;
		return;
	}
	if(l_t[e]){
		l_t[e]=0;
		l_t[e*2]=l_t[e*2+1]=1;
		left[e*2]=left[e*2+1]=left[e];
	}
	updateL(a,(a+b)/2,c,d,e*2,f);
	updateL((a+b)/2+1,b,c,d,e*2+1,f);
	left[e]=min(left[e*2],left[e*2+1]);
}
void updateR(int a,int b,int c,int d,int e,int f){
	if(d<a||b<c)return;
	if(c<=a&&b<=d){
		r_t[e]=1;
		right[e]=f;
		return;
	}
	if(r_t[e]){
		r_t[e]=0;
		r_t[e*2]=r_t[e*2+1]=1;
		right[e*2]=right[e*2+1]=right[e];
	}
	updateR(a,(a+b)/2,c,d,e*2,f);
	updateR((a+b)/2+1,b,c,d,e*2+1,f);
	right[e]=max(right[e*2],right[e*2+1]);
}
int getL(int a){
	int L=0;
	int R=65535;
	int ind=1;
	while(L<R){
		if(l_t[ind]){
			l_t[ind]=0;
			l_t[ind*2]=l_t[ind*2+1]=1;
			left[ind*2]=left[ind*2+1]=left[ind];
		}
		if((L+R)/2>=a){
			ind=ind*2;
			R=(L+R)/2;
		}else{
			ind=ind*2+1;
			L=(L+R)/2+1;
		}
	}
	return left[a+65536];
}
int getR(int a){
	int L=0;
	int R=65535;
	int ind=1;
	while(L<R){
		if(r_t[ind]){
			r_t[ind]=0;
			r_t[ind*2]=r_t[ind*2+1]=1;
			right[ind*2]=right[ind*2+1]=right[ind];
		}
		if((L+R)/2>=a){
			ind=ind*2;
			R=(L+R)/2;
		}else{
			ind=ind*2+1;
			L=(L+R)/2+1;
		}
	}
	return right[a+65536];
}
int main(){
	int a,b;
	scanf("%d%d",&a,&b);
	for(int i=0;i<(1<<17);i++)left[i]=999999999;
	for(int i=0;i<(1<<17);i++)right[i]=sz[i]=-999999999;
	for(int i=1;i<=a;i++){
		left[65536+i]=1;
		right[65536+i]=a;
	}
	sz[65537]=a;
	for(int i=65535;i>=1;i--){
		left[i]=min(left[i*2],left[i*2+1]);
		right[i]=max(right[i*2],right[i*2+1]);
		sz[i]=max(sz[i*2],sz[i*2+1]);
	}
	for(int i=0;i<b;i++){
		int c;
		scanf("%d",&c);
		if(c==1){
			int d;
			scanf("%d",&d);
			int at=find(d);
			if(at==-1){
				printf("0\n");
			}else{
				int val=sz[65536+at];
				printf("%d\n",at);
				updateL(0,65535,at,getR(at),1,at+d);
				updateL(0,65535,at,at+d-1,1,999999999);
				updateR(0,65535,at,at+d-1,1,-999999999);
				updateS(0,65535,at,at,1,-999999999);
				updateS(0,65535,at+d,at+d,1,val-d);
			}
		}else{
			int d,e;
			scanf("%d%d",&d,&e);
			int l=min(d,getL(d-1));
			int r=max(d+e-1,getR(d+e));
			updateL(0,65535,l,r,1,l);
			updateR(0,65535,l,r,1,r);
			updateS(0,65535,l+1,r,1,0);
			updateS(0,65535,l,l,1,r-l+1);
		}
	}
}

USACO残り9問になりました。