参考 http://dnizna.javaeye.com/blog/657622 的 写法
/**/
/*
题意:长度为N的01串,Q个操作
0 a b 将[a,b]置0
1 a b 将[a,b]置1
2 a b 将[a,b]内的数翻转,0->1 1->0
3 a b 查询[a,b]内1的个数
4 a b 查询[a,b]内最多的连续1个数
维护max1,maxL1,maxR1 最多连续1的个数,左边最多连续1的个数,右边最多连续1的个数
需要延迟标记 set rev
set = 1 表示置为1
set = 0 表示置为0
set = -1 表示没有置数
rev = 1表示需要翻转
所以在需要修改时,遇到整段修改的,将该段的值更新为正确的
如set 1 的话 sum = right - left +1
然后对于其儿子的,不用更新!直接在该段标记set = 1 表示以后孩子需要更新,但该段已经是正确的值!!!
标记的做法主要就是上面说的了,某一段是正确的,但标记其儿子等都需要修改
每次遇到一条线段时,push_down() ,这样子实现了延迟更新了
如果set = 1,rev = 1这样子并不表明是先set,还是先reverse,就这里的细节了!!
但如果要set的话,必定不需再reverse了
所以在某一段,如果其需要set,更新孩子,将该标记传给孩子,表明孩子的孩子以后需要更新
同时,将孩子的rev = 0
即: rev + set -> set
set + rev -> set + rev
所以push_down()那里的处理顺序是:
if(set)
if(rev)
两者是并列的!!
考虑例子:
[0 4]
[0 2]
先将[0,2]标记(set or rev),接下来是标记[0,4],上面的覆盖下面了
所以为set的话,[0,2]的rev置为0了 rev的话,就传下去
所以push_down()的if 是并列的
*/
#include < cstdio >
#include < cstring >
#include < algorithm >
using namespace std;
const int MAXN = 100010 ;
int x[MAXN];
struct Node
{
int max0,maxL0,maxR0;
int max1,maxL1,maxR1;
int sum,set,rev;
} ;
struct SegTree
{
Node nodes[MAXN*3];
void update(int p,int left,int right)
{
if(left == right)return;
nodes[p].sum = nodes[2*p].sum + nodes[2*p+1].sum;
int mid = (left+right)>>1;
nodes[p].maxL0 = nodes[2*p].maxL0;
if(nodes[p].maxL0 == mid-left+1)nodes[p].maxL0 += nodes[2*p+1].maxL0;
nodes[p].maxR0 = nodes[2*p+1].maxR0;
if(nodes[p].maxR0 == right-mid)nodes[p].maxR0 += nodes[2*p].maxR0;
nodes[p].max0 = max(nodes[2*p].max0,nodes[2*p+1].max0);
nodes[p].max0 = max(nodes[p].max0,nodes[2*p].maxR0+nodes[2*p+1].maxL0);
nodes[p].maxL1 = nodes[2*p].maxL1;
if(nodes[p].maxL1 == mid-left+1)nodes[p].maxL1 += nodes[2*p+1].maxL1;
nodes[p].maxR1 = nodes[2*p+1].maxR1;
if(nodes[p].maxR1 == right-mid)nodes[p].maxR1 += nodes[2*p].maxR1;
nodes[p].max1 = max(nodes[2*p].max1,nodes[2*p+1].max1);
nodes[p].max1 = max(nodes[p].max1,nodes[2*p].maxR1+nodes[2*p+1].maxL1);
}
void push_down(int p,int left,int right)
{
if(left == right)return;
int mid = (left+right)>>1;
//set 与 rev 是并列的!!!
if(nodes[p].set != -1)
{
int val = nodes[p].set;
nodes[p].set = -1;
nodes[2*p].set = nodes[2*p+1].set = val;
nodes[2*p].rev = nodes[2*p+1].rev = 0;//将孩子的rev置为0
nodes[2*p].sum = val==1?mid-left+1:0;
nodes[2*p].max0 = nodes[2*p].maxL0 = nodes[2*p].maxR0 = val==0?mid-left+1:0;
nodes[2*p].max1 = nodes[2*p].maxL1 = nodes[2*p].maxR1 = val==1?mid-left+1:0;
nodes[2*p+1].sum = val==1?right-mid:0;
nodes[2*p+1].max0 = nodes[2*p+1].maxL0 = nodes[2*p+1].maxR0 = val==0?right-mid:0;
nodes[2*p+1].max1 = nodes[2*p+1].maxL1 = nodes[2*p+1].maxR1 = val==1?right-mid:0;
}
if(nodes[p].rev)
{
nodes[p].rev = false;
nodes[2*p].rev ^= 1;//这里是翻转!!!
nodes[2*p+1].rev ^= 1;
nodes[2*p].sum = mid-left+1 - nodes[2*p].sum;
swap(nodes[2*p].max0,nodes[2*p].max1);
swap(nodes[2*p].maxL0,nodes[2*p].maxL1);
swap(nodes[2*p].maxR0,nodes[2*p].maxR1);
nodes[2*p+1].sum = right - mid - nodes[2*p+1].sum;
swap(nodes[2*p+1].max0,nodes[2*p+1].max1);
swap(nodes[2*p+1].maxL0,nodes[2*p+1].maxL1);
swap(nodes[2*p+1].maxR0,nodes[2*p+1].maxR1);
}
}
void build(int p,int left,int right)
{
nodes[p].set = -1;
nodes[p].rev = 0;
if(left == right)
{
nodes[p].sum = x[left];
nodes[p].max0 = nodes[p].maxL0 = nodes[p].maxR0 = (x[left]==0);
nodes[p].max1 = nodes[p].maxL1 = nodes[p].maxR1 = (x[left]==1);
return;
}
int mid = (left+right)>>1;
build(2*p,left,mid);
build(2*p+1,mid+1,right);
update(p,left,right);
}
void change(int p,int left,int right,int l,int r,int op)
{
push_down(p,left,right);
if(l<=left && right<=r)
{
if(op == 2)
{
nodes[p].rev = true;
nodes[p].sum = right - left + 1 - nodes[p].sum;
swap(nodes[p].max0,nodes[p].max1);
swap(nodes[p].maxL0,nodes[p].maxL1);
swap(nodes[p].maxR0,nodes[p].maxR1);
}
else
{
nodes[p].set = op;
nodes[p].sum = op==1?right-left+1:0;
nodes[p].max0 = nodes[p].maxL0 = nodes[p].maxR0 = op==0?right-left+1:0;
nodes[p].max1 = nodes[p].maxL1 = nodes[p].maxR1 = op==1?right-left+1:0;
}
return;
}
int mid = (left+right) >>1;
if(l>mid)change(2*p+1,mid+1,right,l,r,op);
else if(r<=mid)change(2*p,left,mid,l,r,op);
else
{
change(2*p,left,mid,l,mid,op);
change(2*p+1,mid+1,right,mid+1,r,op);
}
update(p,left,right);
}
int query(int p,int left,int right,int l,int r,int op)
{
push_down(p,left,right);
if(l<=left && right<=r)
{
if(op==3)return nodes[p].sum;
return nodes[p].max1;
}
int mid = (left+right)>>1;
if(l>mid)return query(2*p+1,mid+1,right,l,r,op);
if(r<=mid)return query(2*p,left,mid,l,r,op);
if(op==3)return query(2*p,left,mid,l,mid,op)+query(2*p+1,mid+1,right,mid+1,r,op);
int ans = max(query(2*p,left,mid,l,mid,op),query(2*p+1,mid+1,right,mid+1,r,op));
int L = min(nodes[2*p].maxR1,mid+1-l);
int R = min(nodes[2*p+1].maxL1,r-mid);
ans = max(ans,L+R);
return ans;
}
} ;
SegTree segTree;
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("in","r",stdin);
#endif
int T;
for(scanf("%d",&T);T--;)
{
int N,Q;
int q,a,b;
scanf("%d%d",&N,&Q);
for(int i=0;i<N;i++)
scanf("%d",&x[i]);
segTree.build(1,0,N-1);
for(int i=0;i<Q;i++)
{
scanf("%d%d%d",&q,&a,&b);
if(q<=2)segTree.change(1,0,N-1,a,b,q);
else printf("%d\n",segTree.query(1,0,N-1,a,b,q));
}
}
return 0;
}
题意:长度为N的01串,Q个操作
0 a b 将[a,b]置0
1 a b 将[a,b]置1
2 a b 将[a,b]内的数翻转,0->1 1->0
3 a b 查询[a,b]内1的个数
4 a b 查询[a,b]内最多的连续1个数
维护max1,maxL1,maxR1 最多连续1的个数,左边最多连续1的个数,右边最多连续1的个数
需要延迟标记 set rev
set = 1 表示置为1
set = 0 表示置为0
set = -1 表示没有置数
rev = 1表示需要翻转
所以在需要修改时,遇到整段修改的,将该段的值更新为正确的
如set 1 的话 sum = right - left +1
然后对于其儿子的,不用更新!直接在该段标记set = 1 表示以后孩子需要更新,但该段已经是正确的值!!!
标记的做法主要就是上面说的了,某一段是正确的,但标记其儿子等都需要修改
每次遇到一条线段时,push_down() ,这样子实现了延迟更新了
如果set = 1,rev = 1这样子并不表明是先set,还是先reverse,就这里的细节了!!
但如果要set的话,必定不需再reverse了
所以在某一段,如果其需要set,更新孩子,将该标记传给孩子,表明孩子的孩子以后需要更新
同时,将孩子的rev = 0
即: rev + set -> set
set + rev -> set + rev
所以push_down()那里的处理顺序是:
if(set)
if(rev)
两者是并列的!!
考虑例子:
[0 4]
[0 2]
先将[0,2]标记(set or rev),接下来是标记[0,4],上面的覆盖下面了
所以为set的话,[0,2]的rev置为0了 rev的话,就传下去
所以push_down()的if 是并列的
*/
#include < cstdio >
#include < cstring >
#include < algorithm >
using namespace std;
const int MAXN = 100010 ;
int x[MAXN];
struct Node
{
int max0,maxL0,maxR0;
int max1,maxL1,maxR1;
int sum,set,rev;
} ;
struct SegTree
{
Node nodes[MAXN*3];
void update(int p,int left,int right)
{
if(left == right)return;
nodes[p].sum = nodes[2*p].sum + nodes[2*p+1].sum;
int mid = (left+right)>>1;
nodes[p].maxL0 = nodes[2*p].maxL0;
if(nodes[p].maxL0 == mid-left+1)nodes[p].maxL0 += nodes[2*p+1].maxL0;
nodes[p].maxR0 = nodes[2*p+1].maxR0;
if(nodes[p].maxR0 == right-mid)nodes[p].maxR0 += nodes[2*p].maxR0;
nodes[p].max0 = max(nodes[2*p].max0,nodes[2*p+1].max0);
nodes[p].max0 = max(nodes[p].max0,nodes[2*p].maxR0+nodes[2*p+1].maxL0);
nodes[p].maxL1 = nodes[2*p].maxL1;
if(nodes[p].maxL1 == mid-left+1)nodes[p].maxL1 += nodes[2*p+1].maxL1;
nodes[p].maxR1 = nodes[2*p+1].maxR1;
if(nodes[p].maxR1 == right-mid)nodes[p].maxR1 += nodes[2*p].maxR1;
nodes[p].max1 = max(nodes[2*p].max1,nodes[2*p+1].max1);
nodes[p].max1 = max(nodes[p].max1,nodes[2*p].maxR1+nodes[2*p+1].maxL1);
}
void push_down(int p,int left,int right)
{
if(left == right)return;
int mid = (left+right)>>1;
//set 与 rev 是并列的!!!
if(nodes[p].set != -1)
{
int val = nodes[p].set;
nodes[p].set = -1;
nodes[2*p].set = nodes[2*p+1].set = val;
nodes[2*p].rev = nodes[2*p+1].rev = 0;//将孩子的rev置为0
nodes[2*p].sum = val==1?mid-left+1:0;
nodes[2*p].max0 = nodes[2*p].maxL0 = nodes[2*p].maxR0 = val==0?mid-left+1:0;
nodes[2*p].max1 = nodes[2*p].maxL1 = nodes[2*p].maxR1 = val==1?mid-left+1:0;
nodes[2*p+1].sum = val==1?right-mid:0;
nodes[2*p+1].max0 = nodes[2*p+1].maxL0 = nodes[2*p+1].maxR0 = val==0?right-mid:0;
nodes[2*p+1].max1 = nodes[2*p+1].maxL1 = nodes[2*p+1].maxR1 = val==1?right-mid:0;
}
if(nodes[p].rev)
{
nodes[p].rev = false;
nodes[2*p].rev ^= 1;//这里是翻转!!!
nodes[2*p+1].rev ^= 1;
nodes[2*p].sum = mid-left+1 - nodes[2*p].sum;
swap(nodes[2*p].max0,nodes[2*p].max1);
swap(nodes[2*p].maxL0,nodes[2*p].maxL1);
swap(nodes[2*p].maxR0,nodes[2*p].maxR1);
nodes[2*p+1].sum = right - mid - nodes[2*p+1].sum;
swap(nodes[2*p+1].max0,nodes[2*p+1].max1);
swap(nodes[2*p+1].maxL0,nodes[2*p+1].maxL1);
swap(nodes[2*p+1].maxR0,nodes[2*p+1].maxR1);
}
}
void build(int p,int left,int right)
{
nodes[p].set = -1;
nodes[p].rev = 0;
if(left == right)
{
nodes[p].sum = x[left];
nodes[p].max0 = nodes[p].maxL0 = nodes[p].maxR0 = (x[left]==0);
nodes[p].max1 = nodes[p].maxL1 = nodes[p].maxR1 = (x[left]==1);
return;
}
int mid = (left+right)>>1;
build(2*p,left,mid);
build(2*p+1,mid+1,right);
update(p,left,right);
}
void change(int p,int left,int right,int l,int r,int op)
{
push_down(p,left,right);
if(l<=left && right<=r)
{
if(op == 2)
{
nodes[p].rev = true;
nodes[p].sum = right - left + 1 - nodes[p].sum;
swap(nodes[p].max0,nodes[p].max1);
swap(nodes[p].maxL0,nodes[p].maxL1);
swap(nodes[p].maxR0,nodes[p].maxR1);
}
else
{
nodes[p].set = op;
nodes[p].sum = op==1?right-left+1:0;
nodes[p].max0 = nodes[p].maxL0 = nodes[p].maxR0 = op==0?right-left+1:0;
nodes[p].max1 = nodes[p].maxL1 = nodes[p].maxR1 = op==1?right-left+1:0;
}
return;
}
int mid = (left+right) >>1;
if(l>mid)change(2*p+1,mid+1,right,l,r,op);
else if(r<=mid)change(2*p,left,mid,l,r,op);
else
{
change(2*p,left,mid,l,mid,op);
change(2*p+1,mid+1,right,mid+1,r,op);
}
update(p,left,right);
}
int query(int p,int left,int right,int l,int r,int op)
{
push_down(p,left,right);
if(l<=left && right<=r)
{
if(op==3)return nodes[p].sum;
return nodes[p].max1;
}
int mid = (left+right)>>1;
if(l>mid)return query(2*p+1,mid+1,right,l,r,op);
if(r<=mid)return query(2*p,left,mid,l,r,op);
if(op==3)return query(2*p,left,mid,l,mid,op)+query(2*p+1,mid+1,right,mid+1,r,op);
int ans = max(query(2*p,left,mid,l,mid,op),query(2*p+1,mid+1,right,mid+1,r,op));
int L = min(nodes[2*p].maxR1,mid+1-l);
int R = min(nodes[2*p+1].maxL1,r-mid);
ans = max(ans,L+R);
return ans;
}
} ;
SegTree segTree;
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("in","r",stdin);
#endif
int T;
for(scanf("%d",&T);T--;)
{
int N,Q;
int q,a,b;
scanf("%d%d",&N,&Q);
for(int i=0;i<N;i++)
scanf("%d",&x[i]);
segTree.build(1,0,N-1);
for(int i=0;i<Q;i++)
{
scanf("%d%d%d",&q,&a,&b);
if(q<=2)segTree.change(1,0,N-1,a,b,q);
else printf("%d\n",segTree.query(1,0,N-1,a,b,q));
}
}
return 0;
}