【BZOJ4592】[Shoi2015]脑洞治疗仪 线段树

时间:2021-07-24 14:46:41

【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

题解:直接用线段树模拟就行,这里只说1操作。

先统计原位置有多少个have,再将原位置清空。如果能将目标位置填满,直接填满即可。否则我们需要找到应该填到哪里,即第have个空位的位置。这个可以在线段树上二分实现。

#include <cstdio>
#include <cstring>
#include <iostream>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=200010;
int n,m;
struct node
{
int sum,tag,ls,rs,sm;
node () {sum=ls=rs=sm=0,tag=-1;}
node operator + (const node &b) const
{
node c;
c.sum=sum+b.sum;
if(sum&&sum==ls&&sum==rs) c.ls=sum+b.ls;
else c.ls=ls;
if(b.sum&&b.sum==b.ls&&b.sum==b.rs) c.rs=rs+b.sum;
else c.rs=b.rs;
c.sm=max(max(sm,b.sm),rs+b.ls);
return c;
}
}s[maxn<<2];
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
inline void cover(int l,int r,int x,int v)
{
if(v) s[x].tag=1,s[x].sum=s[x].ls=s[x].rs=s[x].sm=r-l+1;
else s[x].tag=s[x].sum=s[x].ls=s[x].rs=s[x].sm=0;
}
inline void pushdown(int l,int r,int x)
{
if(s[x].tag!=-1)
{
int mid=(l+r)>>1;
cover(l,mid,lson,s[x].tag),cover(mid+1,r,rson,s[x].tag),s[x].tag=-1;
}
}
void updata(int l,int r,int x,int a,int b,int c)
{
if(a>b) return ;
if(a<=l&&r<=b)
{
cover(l,r,x,c);
return ;
}
pushdown(l,r,x);
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,lson,a,b,c);
if(b>mid) updata(mid+1,r,rson,a,b,c);
s[x]=s[lson]+s[rson];
}
node query(int l,int r,int x,int a,int b)
{
if(a>b) return node();
if(a<=l&&r<=b) return s[x];
pushdown(l,r,x);
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,lson,a,b);
if(a>mid) return query(mid+1,r,rson,a,b);
return query(l,mid,lson,a,b)+query(mid+1,r,rson,a,b);
}
int find(int l,int r,int x,int a)
{
if(!a) return 0;
if(l==r) return l;
pushdown(l,r,x);
int mid=(l+r)>>1;
if(s[lson].sum>=a) return find(l,mid,lson,a);
return find(mid+1,r,rson,a-s[lson].sum);
}
int main()
{
int i,a,b,c,d,op,hav,ned;
n=rd(),m=rd();
for(i=1;i<=m;i++)
{
op=rd(),a=rd(),b=rd();
if(op==0) updata(1,n,1,a,b,1);
if(op==1)
{
c=rd(),d=rd();
hav=b-a+1-query(1,n,1,a,b).sum;
updata(1,n,1,a,b,1);
ned=query(1,n,1,c,d).sum;
if(hav>=ned) updata(1,n,1,c,d,0);
else updata(1,n,1,c,find(1,n,1,query(1,n,1,1,c-1).sum+hav),0);
}
if(op==2) printf("%d\n",query(1,n,1,a,b).sm);
}
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