BZOJ4592 [Shoi2015]脑洞治疗仪

41 篇文章 0 订阅

进行治疗实际上相当于用1覆盖一段区间,这段区间内原有的1的个数加上挖出来的1的个数等于这段区间的长度,并且这段区间的长度最长为治疗的区间长度

记录一下还剩多少挖出来的1,然后在线段树上爬出这个区间就可以了,因为是线段树上,所以找到一个区间是log的

知道了一段区间的长度,区间里有多少1,还剩多少脑组织,就能知道这段区间是否被完全覆盖

需要判断是否还剩脑组织,如果没了就返回,要不然复杂度不对

复杂度 O(m log n)

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
using namespace std;
#define MAXN 200010
#define MAXM 1010
#define ll long long
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
int n,m;
int s[MAXN<<2],mx[MAXN<<2],mxl[MAXN<<2],mxr[MAXN<<2],ch[MAXN<<2],s0[MAXN<<2];
int MX,MXR;
int V;
inline void ud(int x,int y,int z){
	int mid=y+z>>1;
	s[x]=s[x<<1]+s[x<<1|1];
	s0[x]=s0[x<<1]+s0[x<<1|1];
	mx[x]=max(mxr[x<<1]+mxl[x<<1|1],max(mx[x<<1],mx[x<<1|1]));
	mxl[x]=mxl[x<<1];
	mxr[x]=mxr[x<<1|1];
	if(s0[x<<1]==mid-y+1){
		mxl[x]=s0[x<<1]+mxl[x<<1|1];
	}
	if(s0[x<<1|1]==z-mid){
		mxr[x]=s0[x<<1|1]+mxr[x<<1];
	}
}
inline void toch(int x,int y,int z,int cv){
	s0[x]=mx[x]=mxl[x]=mxr[x]=(z-y+1)*(cv^1);
	s[x]=(z-y+1)*cv;
	ch[x]=cv;
}
inline void pd(int x,int y,int z){
	if(~ch[x]){
		int mid=y+z>>1;
		toch(x<<1,y,mid,ch[x]);
		toch(x<<1|1,mid+1,z,ch[x]);
		ch[x]=-1;
	}
}
void build(int x,int y,int z){
	ch[x]=-1;
	if(y==z){
		s0[x]=mx[x]=mxl[x]=mxr[x]=0;
		s[x]=1;
		return ;
	}
	int mid=y+z>>1;
	build(x<<1,y,mid);
	build(x<<1|1,mid+1,z);
	ud(x,y,z);
}
void change(int x,int y,int z,int l,int r,int cv){
	if(y==l&&z==r){
		toch(x,y,z,cv);
		return ;
	}
	pd(x,y,z);
	int mid=y+z>>1;
	if(r<=mid){
		change(x<<1,y,mid,l,r,cv);
	}else if(l>mid){
		change(x<<1|1,mid+1,z,l,r,cv);
	}else{
		change(x<<1,y,mid,l,mid,cv);
		change(x<<1|1,mid+1,z,mid+1,r,cv);
	}
	ud(x,y,z);
}
int ask(int x,int y,int z,int l,int r){
	if(y==l&&z==r){
		return s[x];
	}
	pd(x,y,z);
	int mid=y+z>>1;
	if(r<=mid){
		return ask(x<<1,y,mid,l,r);
	}else if(l>mid){
		return ask(x<<1|1,mid+1,z,l,r);
	}else{
		return ask(x<<1,y,mid,l,mid)+ask(x<<1|1,mid+1,z,mid+1,r);
	}
	ud(x,y,z);
}
void toask(int x,int y,int z,int l,int r){
	if(y==l&&z==r){
		MX=max(MX,max(MXR+mxl[x],mx[x]));
		if(s0[x]==z-y+1){
			MXR+=z-y+1;
		}else{
			MXR=mxr[x];
		}
		return ;
	}
	pd(x,y,z);
	int mid=y+z>>1;
	if(r<=mid){
		toask(x<<1,y,mid,l,r);
	}else if(l>mid){
		toask(x<<1|1,mid+1,z,l,r);
	}else{
		toask(x<<1,y,mid,l,mid);
		toask(x<<1|1,mid+1,z,mid+1,r);
	}
	ud(x,y,z);
}
void dang(int x,int y,int z){
	if(y==z){
		if(V+s[x]>=z-y+1){
			V-=z-y+1-s[x];
			toch(x,y,z,1);
		}
		return ;
	}
	pd(x,y,z);
	int mid=y+z>>1;
	if(V+s[x]>=z-y+1){
		V-=z-y+1-s[x];
		toch(x,y,z,1);
		return ;
	}else{
		dang(x<<1,y,mid);
		if(V){
			dang(x<<1|1,mid+1,z);
		}
	}
	ud(x,y,z);
}
void guang(int x,int y,int z,int l,int r){
	if(!V){
		return ;
	}
	if(y==l&&z==r){
		if(V){
			dang(x,y,z);
		}
		return ;
	}
	pd(x,y,z);
	int mid=y+z>>1;
	if(r<=mid){
		guang(x<<1,y,mid,l,r);
	}else if(l>mid){
		guang(x<<1|1,mid+1,z,l,r);
	}else{
		guang(x<<1,y,mid,l,mid);
		if(V){
			guang(x<<1|1,mid+1,z,mid+1,r);
		}
	}
	ud(x,y,z);
}
int main(){
	int i,o,x,y,xx,yy;
	scanf("%d%d",&n,&m);
	build(1,1,n);
	for(i=1;i<=m;i++){
		scanf("%d",&o);
		if(o==0){
			scanf("%d%d",&x,&y);
			change(1,1,n,x,y,0);
		}
		if(o==1){
			scanf("%d%d%d%d",&x,&y,&xx,&yy);
			V=ask(1,1,n,x,y);
			change(1,1,n,x,y,0);
			guang(1,1,n,xx,yy);
		}
		if(o==2){
			scanf("%d%d",&x,&y);
			MX=MXR=0;
			toask(1,1,n,x,y);
			printf("%d\n",MX);
		}
	}
	return 0;
}

/*
10 10
0 2 2
0 4 6
0 10 10
2 1 10
1 8 10 1 4
2 1 10
1 1 4 8 10
2 1 10
1 7 10 1 6
2 1 10

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值