poj3667 Hotel

不错的一道线段树。为了计算结果,对线段树结点增加几个域:从该区间左端点开始的连续空区间的长度,从该区间右端点为终点的连续空区间的长度,及该区间内的最大连续空区间的长度。

在每次查询时,先判断最大连续区间是否能够满足要求,为了找到最小的值,先检查左端点开始的空区间长度,如果不满足,那么此时要查询的区间有可能在:左端点的区间中,左端点及右端点共同表示的一段区间中,或右端点的区间中。那么判断的依据依次为:左端点的最大连续空区间长度满足要求,以左端点表示区间的右端点为终点的连续空区间及以右端点表示区间的左端点为起点的连续空区间的长度之和满足要求,如果前两个条件都没有满足,那么目标区间就只可能在右端点中了。

当然,在查询时,是没有必要进行下推标记的操作的,因为只有当当前结点的标记为混合时,查询函数才有可能进行到下一个子结点,而这时是不需要进行下推操作的。

#include
#include
#include
#include
using namespace std;

int n,m;

struct nd{
	int ld,rd;
	int lm,rm,mm;
	int flg;
};
nd tre[200000];

void gentre(int ni,int l,int r){
	nd& pt=tre[ni];
	pt.ld=l,pt.rd=r;
	pt.mm=pt.lm=pt.rm=r-l+1;
	pt.flg=0;
	if(l!=r){
		int m=(l+r)>>1;
		gentre(ni<<1,l,m);
		gentre(ni<<1|1,m+1,r);
	}
};

void upd(int ni,int l,int r,int ci){
	nd& pt=tre[ni];
	int ld=pt.ld,rd=pt.rd,md=(ld+rd)>>1;
	if(ld==l&&rd==r){
		pt.flg=ci;
		if(ci)
			pt.lm=pt.rm=pt.mm=0;
		else
			pt.lm=pt.rm=pt.mm=rd-ld+1;
		return;
	}
	nd& lpt=tre[ni<<1],& rpt=tre[ni<<1|1];
	if(pt.flg!=2){
		lpt.flg=rpt.flg=pt.flg;
		if(pt.flg){
			lpt.lm=lpt.rm=lpt.mm=
				rpt.lm=rpt.rm=rpt.mm=0;
		}
		else{
			lpt.lm=lpt.rm=lpt.mm=(md-ld)+1;
			rpt.lm=rpt.rm=rpt.mm=rd-md;
		}
	}
	if(l>md)
		upd(ni<<1|1,l,r,ci);
	else if(r<=md)
		upd(ni<<1,l,r,ci);
	else
		upd(ni<<1,l,md,ci),
		upd(ni<<1|1,md+1,r,ci);
	if(lpt.flg==rpt.flg){
		pt.flg=lpt.flg;
		if(!lpt.flg)
			pt.lm=pt.rm=pt.mm=rd-ld+1;
		else if(lpt.flg==1)
			pt.lm=pt.rm=pt.mm=0;
		else{
			pt.lm=lpt.lm,pt.rm=rpt.rm;
			pt.mm=max(lpt.mm,max(rpt.mm,lpt.rm+rpt.lm));
		}
	}
	else{
		pt.flg=2;
		if(!lpt.flg)
			pt.lm=lpt.mm+rpt.lm;
		else
			pt.lm=lpt.lm;
		if(!rpt.flg)
			pt.rm=lpt.rm+rpt.mm;
		else
			pt.rm=rpt.rm;
		pt.mm=max(lpt.rm+rpt.lm,max(pt.lm,pt.rm));
		pt.mm=max(pt.mm,max(lpt.mm,rpt.mm));
	}
};

int fr(int ni,int ds){
	nd& pt=tre[ni];
	if(pt.mm=ds)
		return pt.ld;
	nd& lpt=tre[ni<<1],& rpt=tre[ni<<1|1];
	if(lpt.mm>=ds)
		return fr(ni<<1,ds);
	if(lpt.rm+rpt.lm>=ds)
		return lpt.rd-lpt.rm+1;
	return fr(ni<<1|1,ds);
};

bool solve(){
	if(scanf("%d %d",&n,&m)==-1)
		return 0;
	gentre(1,1,n);
	int ci,ca,cb,ts;
	for(int i=0;i

你可能感兴趣的:(poj3667 Hotel)