POJ 3667

维护左连续,右连续区间最大值,同时维护区间内最大的连续区间值。同时是使用标记法完成。很强大。

注意出现的状态-1,很巧妙,代表该结点不能再下传了,即不符合下传条件。

#include <cstdio>  
#include <cstring>  
#include <cctype>  
#include <algorithm>  
using namespace std;  
   
const int maxn = 55555;  
int lsum[maxn<<2] , rsum[maxn<<2] , msum[maxn<<2];  
int cover[maxn<<2]; 

void build(int rt,int l,int r){
	cover[rt]=-1;
	lsum[rt]=rsum[rt]=msum[rt]=r-l+1;
	if(l==r) return;
	int m=(l+r)>>1;
	build(rt<<1,l,m);
	build(rt<<1|1,m+1,r);
}

void PushDown(int rt,int m){
	if(cover[rt]!=-1){
		cover[rt<<1]=cover[rt<<1|1]=cover[rt];
		lsum[rt<<1]=rsum[rt<<1]=msum[rt<<1]=cover[rt]?0:(m-(m>>1));
		lsum[rt<<1|1]=rsum[rt<<1|1]=msum[rt<<1|1]=cover[rt]?0:(m>>1);
		cover[rt]=-1;
	}
}

void PushUp(int rt,int m){
	lsum[rt]=lsum[rt<<1];
	rsum[rt]=rsum[rt<<1|1];
	if(lsum[rt]==(m-(m>>1))) lsum[rt]+=lsum[rt<<1|1];
	if(rsum[rt]==(m>>1)) rsum[rt]+=rsum[rt<<1];
	msum[rt]=max(lsum[rt<<1|1]+rsum[rt<<1],max(msum[rt<<1],msum[rt<<1|1]));
	msum[rt]=max(msum[rt],lsum[rt]);
	msum[rt]=max(msum[rt],rsum[rt]);
}

int query(int rt,int l,int r,int w){
	if(l==r) return l;
	PushDown(rt,r-l+1);
	int m=(l+r)>>1;
	if(msum[rt<<1]>=w) return query(rt<<1,l,m,w);
	else if(rsum[rt<<1]+lsum[rt<<1|1]>=w) return m-rsum[rt<<1]+1;
	return query(rt<<1|1,m+1,r,w); 
}

void update(int rt,int L,int R,int l,int r,int c){
	if(L<=l&&r<=R){
		cover[rt]=c;
		lsum[rt]=rsum[rt]=msum[rt]=c?0:r-l+1;
		return ;
	}
	PushDown(rt,r-l+1);
	int m=(l+r)>>1;
	if(L<=m) update(rt<<1,L,R,l,m,c);
	if(m<R) update(rt<<1|1,L,R,m+1,r,c);
	PushUp(rt,r-l+1);
}

int main(){
	int n,m,op,a,b;
	while(scanf("%d%d",&n,&m)!=EOF){
		build(1,1,n);
		for(int i=1;i<=m;i++){
			scanf("%d",&op);
			if(op==1){
				scanf("%d",&a);
				if(msum[1]>=a){
					int p=query(1,1,n,a);
					update(1,p,p+a-1,1,n,1);
					printf("%d
",p);
				}
				else printf("0
");
			}
			else{
				scanf("%d%d",&a,&b);
				update(1,a,a+b-1,1,n,0);
			}
		}
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/jie-dcai/p/4320097.html