BZOJ4592: [Shoi2015]脑洞治疗仪

BZOJ4592: [Shoi2015]脑洞治疗仪

Description

曾经发明了自动刷题机的发明家SHTSC又公开了他的新发明:脑洞治疗仪--一种可以治疗他因为发明而日益增大的脑洞的神秘装置。
为了简单起见,我们将大脑视作一个01序列。1代表这个位置的脑组织正常工作,0代表这是一块脑洞。
1 0 1 0 0 0 1 1 1 0
脑洞治疗仪修补某一块脑洞的基本工作原理就是将另一块连续区域挖出,将其中正常工作的脑组织填补在这块脑洞中。
(所以脑洞治疗仪是脑洞的治疗仪?)
例如,用上面第8号位置到第10号位置去修补第1号位置到第4号位置的脑洞。我们就会得到:
1 1 1 1 0 0 1 0 0 0
如果再用第1号位置到第4号位置去修补第8号位置到第10号位置:
0 0 0 0 0 0 1 1 1 1
这是因为脑洞治疗仪会把多余出来的脑组织直接扔掉。
如果再用第7号位置到第10号位置去填补第1号位置到第6号位置:
1 1 1 1 0 0 0 0 0 0
这是因为如果新脑洞挖出来的脑组织不够多,脑洞治疗仪仅会尽量填补位置比较靠前的脑洞。
假定初始时SHTSC并没有脑洞,给出一些挖脑洞和脑洞治疗的操作序列,你需要即时回答SHTSC的问题:
在大脑某个区间中最大的连续脑洞区域有多大。

Input

第一行两个整数n,m。表示SHTSC的大脑可分为从1到n编号的n个连续区域。有m个操作。
以下m行每行是下列三种格式之一。
0 l r :SHTSC挖了一个从l到r的脑洞。
1 l0 r0 l1 r2 :SHTSC进行了一次脑洞治疗,用从l0到r0的脑组织修补l1到r1的脑洞。
2 l r :SHTSC询问l到r这段区间最大的脑洞有多大。
n,m <=200000,1<=l<=r<=n

Output

对于每个询问,输出一行一个整数,表示询问区间内最大连续脑洞区域有多大。

Sample Input

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

Sample Output

3
3
6
6

题解Here!

区间操作,当然线段树。
能写线段树没人会写$Splay$的。。。
操作一直接区间覆盖。
操作三维护$lsum,rsum,sum$分别表示区间内从左端点开始最长连续脑洞区域大小,从右端点开始最长连续脑洞区域大小,区间最长连续脑洞区域大小。
维护一下就好。
操作二一眼没看出来怎么搞。
多舍少漏。。。二分一下能填补的长度不就好了?
显然这个区间满足单调性,于是二分出区间。
然后线段树区间修改即可。
于是,就没了?
嗯,没了。
附带码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) a[x].data
#define SIGN(x) a[x].c
#define LSUM(x) a[x].lsum
#define RSUM(x) a[x].rsum
#define SUM(x) a[x].sum
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 200010
using namespace std;
int n,m;
struct Segment_Tree{
	int data,lsum,rsum,sum,c;
	int l,r;
}a[MAXN<<2];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline void pushup(int rt){
	DATA(rt)=DATA(LSON)+DATA(RSON);
	if(LSUM(LSON)!=WIDTH(LSON))LSUM(rt)=LSUM(LSON);
	else LSUM(rt)=LSUM(LSON)+LSUM(RSON);
	if(RSUM(RSON)!=WIDTH(RSON))RSUM(rt)=RSUM(RSON);
	else RSUM(rt)=RSUM(RSON)+RSUM(LSON);
	SUM(rt)=max(max(SUM(LSON),SUM(RSON)),LSUM(RSON)+RSUM(LSON));
}
inline void pushdown(int rt){
	if(SIGN(rt)==-1||LSIDE(rt)==RSIDE(rt))return;
	if(SIGN(rt)){
		DATA(LSON)=WIDTH(LSON);
		SIGN(LSON)=1;
		LSUM(LSON)=RSUM(LSON)=SUM(LSON)=0;
		DATA(RSON)=WIDTH(RSON);
		SIGN(RSON)=1;
		LSUM(RSON)=RSUM(RSON)=SUM(RSON)=0;
	}
	else{
		DATA(LSON)=SIGN(LSON)=0;
		LSUM(LSON)=RSUM(LSON)=SUM(LSON)=WIDTH(LSON);
		DATA(RSON)=SIGN(RSON)=0;
		LSUM(RSON)=RSUM(RSON)=SUM(RSON)=WIDTH(RSON);
	}
	SIGN(rt)=-1;
}
void buildtree(int l,int r,int rt){
	LSIDE(rt)=l;RSIDE(rt)=r;
	SIGN(rt)=-1;
	if(l==r){
		DATA(rt)=1;
		LSUM(rt)=RSUM(rt)=SUM(rt)=0;
		return;
	}
	int mid=l+r>>1;
	buildtree(l,mid,LSON);
	buildtree(mid+1,r,RSON);
	pushup(rt);
}
void update(int l,int r,int c,int rt){
	if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
		DATA(rt)=c*WIDTH(rt);
		SIGN(rt)=c;
		if(c)LSUM(rt)=RSUM(rt)=SUM(rt)=0;
		else LSUM(rt)=RSUM(rt)=SUM(rt)=WIDTH(rt);
		return;
	}
	pushdown(rt);
	int mid=LSIDE(rt)+RSIDE(rt)>>1;
	if(l<=mid)update(l,r,c,LSON);
	if(mid<r)update(l,r,c,RSON);
	pushup(rt);
}
int query_sum(int l,int r,int rt){
	if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
	pushdown(rt);
	int ans=0,mid=LSIDE(rt)+RSIDE(rt)>>1;
	if(l<=mid)ans+=query_sum(l,r,LSON);
	if(mid<r)ans+=query_sum(l,r,RSON);
	return ans;
}
Segment_Tree query(int l,int r,int rt){
	if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return a[rt];
	pushdown(rt);
	int mid=LSIDE(rt)+RSIDE(rt)>>1;
	Segment_Tree lson={0},rson={0},ans={0};
	if(l<=mid)lson=query(l,r,LSON);
	if(mid<r)rson=query(l,r,RSON);
	if(lson.lsum!=WIDTH(LSON))ans.lsum=lson.lsum;
	else ans.lsum=lson.lsum+rson.lsum;
	if(rson.rsum!=WIDTH(RSON))ans.rsum=rson.rsum;
	else ans.rsum=rson.rsum+lson.rsum;
	ans.sum=max(max(lson.sum,rson.sum),lson.rsum+rson.lsum);
	return ans;
}
void fix(int l0,int r0,int l1,int r1){
	int l=1,r=r1-l1+1,len=0,s=query_sum(l0,r0,1);
	if(!s)return;
	update(l0,r0,0,1);
	while(l<=r){
		int mid=l+r>>1;
		if(mid-query_sum(l1,l1+mid-1,1)<=s){len=mid;l=mid+1;}
		else r=mid-1;
	}
	update(l1,l1+len-1,1,1);
}
void work(){
	int f,x,y,l,r;
	while(m--){
		f=read();l=read();r=read();
		if(f==0)update(l,r,0,1);
		else if(f==1){
			x=read();y=read();
			fix(l,r,x,y);
		}
		else printf("%d
",query(l,r,1).sum);
	}
}
void init(){
	n=read();m=read();
	buildtree(1,n,1);
}
int main(){
	init();
	work();
	return 0;
}
原文地址:https://www.cnblogs.com/Yangrui-Blog/p/10502796.html