考虑需要资瓷哪些操作:区间赋值为0;统计区间1的个数;将区间前k个0变为1;询问区间最长全0子串。于是线段树维护区间1的个数、0的个数、最长前缀后缀全0子串即可。稍微困难的是用一个log实现将区间前k个0变为1,线段树上二分尽量往左边改即可,可以令修改函数返回值为剩余能改的1的个数。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 200010
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int n,m,L[N<<],R[N<<];
struct data{int sum0,sum1,pre,suf,len,lazy;
}tree[N<<];
void update(int k,int x)
{
if (x==)
{
tree[k].sum0=tree[k].pre=tree[k].suf=tree[k].len=R[k]-L[k]+;
tree[k].sum1=;
}
else
{
tree[k].sum0=tree[k].pre=tree[k].suf=tree[k].len=;
tree[k].sum1=R[k]-L[k]+;
}
tree[k].lazy=x;
}
void up(int k)
{
tree[k].sum0=tree[k<<].sum0+tree[k<<|].sum0;
tree[k].sum1=tree[k<<].sum1+tree[k<<|].sum1;
if (tree[k<<].pre==R[k<<]-L[k<<]+) tree[k].pre=tree[k<<].pre+tree[k<<|].pre;
else tree[k].pre=tree[k<<].pre;
if (tree[k<<|].suf==R[k<<|]-L[k<<|]+) tree[k].suf=tree[k<<|].suf+tree[k<<].suf;
else tree[k].suf=tree[k<<|].suf;
tree[k].len=max(max(tree[k<<].len,tree[k<<|].len),tree[k<<].suf+tree[k<<|].pre);
}
void down(int k)
{
update(k<<,tree[k].lazy);
update(k<<|,tree[k].lazy);
tree[k].lazy=-;
}
void build(int k,int l,int r)
{
L[k]=l,R[k]=r;tree[k].lazy=-;
if (l==r) {tree[k].sum1=;return;}
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
up(k);
}
void modify(int k,int l,int r)
{
if (L[k]==l&&R[k]==r) {update(k,);return;}
if (~tree[k].lazy) down(k);
int mid=L[k]+R[k]>>;
if (r<=mid) modify(k<<,l,r);
else if (l>mid) modify(k<<|,l,r);
else modify(k<<,l,mid),modify(k<<|,mid+,r);
up(k);
}
int calc(int k,int l,int r)
{
if (L[k]==l&&R[k]==r) return tree[k].sum1;
if (~tree[k].lazy) down(k);
int mid=L[k]+R[k]>>;
if (r<=mid) return calc(k<<,l,r);
else if (l>mid) return calc(k<<|,l,r);
else return calc(k<<,l,mid)+calc(k<<|,mid+,r);
}
int query(int k,int l,int r)
{
if (L[k]==l&&R[k]==r) return tree[k].len;
if (~tree[k].lazy) down(k);
int mid=L[k]+R[k]>>;
if (r<=mid) return query(k<<,l,r);
else if (l>mid) return query(k<<|,l,r);
else return max(max(query(k<<,l,mid),query(k<<|,mid+,r)),min(tree[k<<].suf,mid-l+)+min(tree[k<<|].pre,r-mid));
}
int paint(int k,int l,int r,int x)
{
if (!x) return ;
if (L[k]==l&&R[k]==r&&x>=tree[k].sum0) {x-=tree[k].sum0;update(k,);return x;}
if (~tree[k].lazy) down(k);
int mid=L[k]+R[k]>>;
if (r<=mid) x=paint(k<<,l,r,x);
else if (l>mid) x=paint(k<<|,l,r,x);
else
{
int t=paint(k<<,l,mid,x);
if (t>=) x=paint(k<<|,mid+,r,t);
else x=;
}
up(k);
return x;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4592.in","r",stdin);
freopen("bzoj4592.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read();
build(,,n);
while (m--)
{
int op=read(),l=read(),r=read();
if (op==) modify(,l,r);
else if (op==)
{
int x=read(),y=read();
int k=calc(,l,r);
modify(,l,r);
paint(,x,y,k);
}
else printf("%d\n",query(,l,r));
}
return ;
}