氵谷传送门
网上看到ODT吊打线段树的dalao。。。STO
但我不会ODT所以只能写线段树QAQ
三个操作分别对应:区间赋值为0,区间求1个数赋值为0再在指定区间从左往右填0,查询区间最长0。
第一个和第三个操作比较常规,难点在第二个。
一开始想的是直接统计1个数赋值,但可能被这种hack:
将第五个挖出放在前四个中,最后就应该是1 1 0 1 0,但错误做法会变成 1 1 1 1 0
所以单独写个modify修改,每次找区间零个数与挖出个数比较即可。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
int n,q,ans,rsum;
struct Tree{
int l,r,len;
int lsum,rsum,mids,ans;
int sum;
int cov,num;
friend inline Tree operator+(Tree a,Tree b){
Tree c;
c.lsum=(a.lsum==a.len)?(a.lsum+b.lsum):a.lsum;
c.rsum=(b.rsum==b.len)?(b.rsum+a.rsum):b.rsum;
c.mids=max(a.mids,max(b.mids,a.rsum+b.lsum));
c.ans=max(c.lsum,max(c.rsum,c.mids));
}
}tr[MAXN<<2];
int Read(){
int i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-') f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
#define lc (root<<1)
#define rc (root<<1|1)
#define mid ((l+r)>>1)
void push_up(int root){
tr[root].sum=tr[lc].sum+tr[rc].sum;
tr[root].lsum=(tr[lc].lsum==tr[lc].len)?(tr[lc].lsum+tr[rc].lsum):tr[lc].lsum;
tr[root].rsum=(tr[rc].rsum==tr[rc].len)?(tr[rc].rsum+tr[lc].rsum):tr[rc].rsum;
tr[root].mids=max(tr[lc].mids,max(tr[rc].mids,tr[lc].rsum+tr[rc].lsum));
tr[root].mids=max(tr[root].mids,max(tr[root].lsum,tr[root].rsum));
}
void push_now(int root,int key){
tr[root].cov=1;
tr[root].num=key;
tr[root].lsum=key?0:tr[root].len;
tr[root].rsum=tr[root].mids=tr[root].lsum;
tr[root].sum=key?tr[root].len:0;
}
void push_down(int root){
if(tr[root].cov){
push_now(lc,tr[root].num);
push_now(rc,tr[root].num);
tr[root].cov=0;
}
}
void build(int root,int l,int r){
tr[root].l=l,tr[root].r=r,tr[root].len=r-l+1;
if(l==r){
tr[root].sum=1;
return ;
}
build(lc,l,mid);
build(rc,mid+1,r);
push_up(root);
}
void update(int root,int l,int r,int L,int R,int key){
if(l>R||r<L) return ;
if(L<=l&&r<=R){
push_now(root,key);
return ;
}
push_down(root);
if(R<=mid)
update(lc,l,mid,L,R,key);
else{
if(L>mid)
update(rc,mid+1,r,L,R,key);
else
update(lc,l,mid,L,mid,key),update(rc,mid+1,r,mid+1,R,key);
}
push_up(root);
}
void modify(int root,int l,int r,int L,int R,int &total){
if(!total) return ;
if(L<=l&&r<=R&&total>=tr[root].len-tr[root].sum){
total-=tr[root].len-tr[root].sum;
push_now(root,1);
return ;
}
push_down(root);
if(L<=mid) modify(lc,l,mid,L,R,total);
if(R>mid) modify(rc,mid+1,r,L,R,total);
push_up(root);
}
int query(int root,int l,int r,int L,int R){
if(l>R||r<L) return 0;
if(L<=l&&r<=R) return tr[root].sum;
push_down(root);
if(R<=mid)
return query(lc,l,mid,L,R);
else{
if(L>mid)
return query(rc,mid+1,r,L,R);
else
return query(lc,l,mid,L,mid)+query(rc,mid+1,r,mid+1,R);
}
}
void querymax(int root,int l,int r){
if(l<=tr[root].l&&tr[root].r<=r){
ans=max(ans,tr[root].mids);
ans=max(ans,rsum+tr[root].lsum);
if(tr[root].rsum==tr[root].len) rsum+=tr[root].len;
else rsum=tr[root].rsum;
return ;
}
push_down(root);
int midd=tr[root].l+tr[root].r>>1;
if(l<=midd) querymax(lc,l,r);
if(r>midd) querymax(rc,l,r);
}
int main(){
n=Read(),q=Read();
build(1,1,n);
while(q--){
int cz=Read();
int l=Read(),r=Read();
if(cz==0)
update(1,1,n,l,r,0);
if(cz==2)
ans=0,rsum=0,querymax(1,l,r),cout<<ans<<'\n';
if(cz==1){
int x=Read(),y=Read();
int total=query(1,1,n,l,r);
update(1,1,n,l,r,0);
modify(1,1,n,x,y,total);
}
}
return 0;
}