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
对于每个询问,输出一行一个整数,表示询问区间内最大连续脑洞区域有多大。
线段树维护区间信息:
区间从左开始连续的0个数
区间从右开始连续的0个数
区间从右开始连续的0个数
区间连续0的最大长度
区间0的个数
区间长度
区间被0/1覆盖的标记
支持操作:
区间覆盖0/1
查询区间1的个数
查询区间最长的连续0的长度
#include<cstdio> inline int input(){ int x=0,c=getchar(); while(c>57||c<48)c=getchar(); while(c>47&&c<58)x=x*10+c-48,c=getchar(); return x; } const int N=420000; int n,m,l,r; int c0[N],sz[N],lc[N],rc[N],f1[N],f0[N],ls[N],rs[N],ms[N],p=1,ans=0,pv,ptr; inline int max(int a,int b){return a>b?a:b;} inline void maxs(int&a,int b){if(a<b)a=b;} int build(int L,int R){ int w=p++; if(L<R){ int M=L+R>>1; lc[w]=build(L,M); rc[w]=build(M+1,R); sz[w]=sz[lc[w]]+sz[rc[w]]; }else sz[w]=1; return w; } inline void tag1(int w){ if(!w)return; f1[w]=1;f0[w]=0; c0[w]=ls[w]=rs[w]=ms[w]=0; } inline void tag0(int w){ if(!w)return; f1[w]=0;f0[w]=1; c0[w]=ls[w]=rs[w]=ms[w]=sz[w]; } inline void up(int w){ int l=lc[w],r=rc[w]; ms[w]=max(ms[l],ms[r]); maxs(ms[w],rs[l]+ls[r]); ls[w]=ls[l]; rs[w]=rs[r]; if(ls[l]==sz[l])maxs(ls[w],ls[l]+ls[r]); if(rs[r]==sz[r])maxs(rs[w],rs[l]+rs[r]); c0[w]=c0[l]+c0[r]; sz[w]=sz[l]+sz[r]; } inline void dwn(int w){ if(f1[w]){ f1[w]=0; tag1(lc[w]);tag1(rc[w]); } if(f0[w]){ f0[w]=0; tag0(lc[w]);tag0(rc[w]); } } void set0(int w=1,int L=1,int R=n){ if(l<=L&&R<=r){ tag0(w); return; } dwn(w); int M=L+R>>1; if(l<=M)set0(lc[w],L,M); if(r>M)set0(rc[w],M+1,R); up(w); } void get1(int w=1,int L=1,int R=n){ if(l<=L&&R<=r){ ans+=sz[w]-c0[w]; return; } dwn(w); int M=L+R>>1; if(l<=M)get1(lc[w],L,M); if(r>M)get1(rc[w],M+1,R); } void set1(int w=1,int L=1,int R=n){ if(!ans)return; if(l<=L&&R<=r&&c0[w]<=ans){ ans-=c0[w]; tag1(w); return; } dwn(w); int M=L+R>>1; if(l<=M)set1(lc[w],L,M); if(r>M)set1(rc[w],M+1,R); up(w); } void query(int w=1,int L=1,int R=n){ if(l<=L&&R<=r){ if(pv){ lc[ptr]=pv;rc[ptr]=w; up(ptr); pv=ptr++; }else pv=w; return; } dwn(w); int M=L+R>>1; if(l<=M)query(lc[w],L,M); if(r>M)query(rc[w],M+1,R); } int main(){ n=input();m=input(); build(1,n); while(m--){ int op=input(); l=input(),r=input(); if(op==0){ set0(); }else if(op==1){ ans=0; get1(); set0(); l=input(),r=input(); set1(); }else{ pv=0,ptr=p; query(); printf("%d\n",ms[pv]); } } return 0; }