搬迁洛谷博客至此
搬迁洛谷博客至此
搬迁洛谷博客至此
重要的事情说三遍
这道题太坑了,我做了加起来一天才AC,找错找过来找过去,发现是pushup()错了(泪奔,最开始我信誓旦旦的说pushup()没错,结果就pushup()最多)
这道题难度中规中矩,就是细节处理非常多,错一点就要找很久。
怎么做?
首先看题,有2种修改(3个),2个询问,最开始我开了两个lazy标记,但其实不用,那样反而更麻烦。开一个lazy标记就够了。
每次修改,就分类讨论:当opt == 0 || opt == 1时直接修改,下传标记;当opt==2时,就要分成3大类,当前区间sign=-1,sign=2,sign=1||sign=0,这里较麻烦,可直接看我代码;
downdate()和上面差不多;
然后一定要注意pushup(),这个函数其实很短,但很重要,处理一定要恰当。
查询连续的1怎么办?
这个做法比较巧妙,可以用一个pre,记录左区间的maxr,向上更新,然后查找右区间的maxl,然后与maxx比较(因为查询的区间可能不能被一个线段树中的区间包含完,所以有可能被分为两段查询)。
上代码(大家不懂的地方,看了代码应该就懂了,代码很容易懂,耐心阅读_):
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls id<<1
#define rs id<<1|1
using namespace std;
const int N=100000+10;
int n,m,a[N],ans=0,pre;
struct node
{
int left,right,sign,sum,maxx,maxl,maxr,maxl0,maxr0,maxx0;
}tree[N*4];
void pushup(int id)//可恶的函数
{
tree[id].sum=tree[ls].sum+tree[rs].sum;
tree[id].maxl=tree[ls].maxl;tree[id].maxl0=tree[ls].maxl0;
if(tree[id].maxl==tree[ls].right-tree[ls].left+1)tree[id].maxl+=tree[rs].maxl;
if(tree[id].maxl0==tree[ls].right-tree[ls].left+1)tree[id].maxl0+=tree[rs].maxl0;
tree[id].maxr=tree[rs].maxr;tree[id].maxr0=tree[rs].maxr0;
if(tree[id].maxr==tree[rs].right-tree[rs].left+1)tree[id].maxr+=tree[ls].maxr;
if(tree[id].maxr0==tree[rs].right-tree[rs].left+1)tree[id].maxr0+=tree[ls].maxr0;
tree[id].maxx=max(tree[ls].maxx,max(tree[rs].maxx,tree[ls].maxr+tree[rs].maxl));
tree[id].maxx0=max(tree[ls].maxx0,max(tree[rs].maxx0,tree[ls].maxr0+tree[rs].maxl0));
}
void built(int id,int l,int r)
{
tree[id].left=l,tree[id].right=r,tree[id].sign=-1;
if(l==r)
{
tree[id].maxl=tree[id].maxr=tree[id].maxx=tree[id].sum=a[l];
tree[id].maxl0=tree[id].maxr0=tree[id].maxx0=(a[l]^1);
return;
}
int mid=(l+r)>>1;
built(ls,l,mid),built(rs,mid+1,r);pushup(id);
}
void change(int id)
{
swap(tree[id].maxl,tree[id].maxl0);swap(tree[id].maxr,tree[id].maxr0);swap(tree[id].maxx,tree[id].maxx0);
tree[id].sum=tree[id].right-tree[id].left+1-tree[id].sum;
}
void downdate(int id)
{
if(tree[id].sign<=1&&tree[id].sign>=0)
{
int tmp;
tmp=(tree[ls].right-tree[ls].left+1);
tree[ls].sign=tree[id].sign;
tree[ls].maxl=tree[ls].maxr=tree[ls].maxx=tree[ls].sum=tmp*tree[id].sign;
tree[ls].maxl0=tree[ls].maxr0=tree[ls].maxx0=tmp*(tree[id].sign^1);
tmp=(tree[rs].right-tree[rs].left+1);
tree[rs].sign=tree[id].sign;
tree[rs].maxl=tree[rs].maxr=tree[rs].maxx=tree[rs].sum=tmp*tree[id].sign;
tree[rs].maxl0=tree[rs].maxr0=tree[rs].maxx0=tmp*(tree[id].sign^1);
}
else if(tree[id].sign==2)
{
if(tree[ls].sign<=1&&tree[ls].sign>=0)
{
int tmp=(tree[ls].right-tree[ls].left+1);
tree[ls].maxl=tree[ls].maxr=tree[ls].maxx=tree[ls].sum=tmp*(tree[ls].sign^1);
tree[ls].maxl0=tree[ls].maxr0=tree[ls].maxx0=tmp*tree[ls].sign;
tree[ls].sign^=1;
}
else if(tree[ls].sign==-1)
{
change(ls);tree[ls].sign=2;
}
else if(tree[ls].sign==2)
{
change(ls);tree[ls].sign=-1;
}
if(tree[rs].sign<=1&&tree[rs].sign>=0)
{
int tmp=(tree[rs].right-tree[rs].left+1);
tree[rs].maxl=tree[rs].maxr=tree[rs].maxx=tree[rs].sum=tmp*(tree[rs].sign^1);
tree[rs].maxl0=tree[rs].maxr0=tree[rs].maxx0=tmp*tree[rs].sign;
tree[rs].sign^=1;
}
else if(tree[rs].sign==-1)
{
change(rs);tree[rs].sign=2;
}
else if(tree[rs].sign==2)
{
change(rs);tree[rs].sign=-1;
}
}tree[id].sign=-1;
}
void update(int id,int l,int r,int opt)
{
if(tree[id].left>r||tree[id].right<l)return;
if(tree[id].left>=l&&tree[id].right<=r)
{
if(opt==0||opt==1)
{
int tmp=(tree[id].right-tree[id].left+1);tree[id].sign=opt;
tree[id].maxl=tree[id].maxr=tree[id].maxx=tree[id].sum=tmp*tree[id].sign;
tree[id].maxl0=tree[id].maxr0=tree[id].maxx0=tmp*(tree[id].sign^1);
}
else if(opt==2)
{
if(tree[id].sign==2)
{
change(id);tree[id].sign=-1;
}
else if(tree[id].sign<=1&&tree[id].sign>=0)
{
int tmp=(tree[id].right-tree[id].left+1);tree[id].sign^=1;
tree[id].maxl=tree[id].maxr=tree[id].maxx=tree[id].sum=tmp*tree[id].sign;
tree[id].maxl0=tree[id].maxr0=tree[id].maxx0=tmp*(tree[id].sign^1);
}
else if(tree[id].sign==-1)
{
change(id);tree[id].sign=2;
}
}
return;
}
if(tree[id].sign>=0)downdate(id);
update(ls,l,r,opt);update(rs,l,r,opt);pushup(id);
}
int querysum(int id,int l,int r)
{
if(tree[id].left>r||tree[id].right<l)return 0;
if(tree[id].left>=l&&tree[id].right<=r)return tree[id].sum;
if(tree[id].sign>=0)downdate(id);
int tmp=querysum(ls,l,r)+querysum(rs,l,r);
return tmp;
}
void querymaxx(int id,int l,int r)
{
if(tree[id].left>r||tree[id].right<l)return;
if(tree[id].left>=l&&tree[id].right<=r)
{
ans=max(ans,max(tree[id].maxx,pre+tree[id].maxl));
if(tree[id].sum==tree[id].right-tree[id].left+1) pre+=tree[id].sum;
else pre=tree[id].maxr;//巧妙地pre
return;
}
if(tree[id].sign>=0)downdate(id);
querymaxx(ls,l,r);querymaxx(rs,l,r);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
built(1,1,n);
for(int i=1;i<=m;i++)
{
int x,y,opt;
scanf("%d%d%d",&opt,&x,&y);x++,y++;
if(opt<=2)update(1,x,y,opt);
if(opt==3)printf("%d\n",querysum(1,x,y));
if(opt==4)ans=0,pre=0,querymaxx(1,x,y),printf("%d\n",ans);
}
}