Sequence operation
Time Limit:5000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Description
lxhgww got a sequence contains n characters which are all '0's or '1's.
We have five operations here:
Change operations:
0 a b change all characters into '0's in [a , b]
1 a b change all characters into '1's in [a , b]
2 a b change all '0's into '1's and change all '1's into '0's in [a, b]
Output operations:
3 a b output the number of '1's in [a, b]
4 a b output the length of the longest continuous '1' string in [a , b]
We have five operations here:
Change operations:
0 a b change all characters into '0's in [a , b]
1 a b change all characters into '1's in [a , b]
2 a b change all '0's into '1's and change all '1's into '0's in [a, b]
Output operations:
3 a b output the number of '1's in [a, b]
4 a b output the length of the longest continuous '1' string in [a , b]
Input
T(T<=10) in the first line is the case number.
Each case has two integers in the first line: n and m (1 <= n , m <= 100000).
The next line contains n characters, '0' or '1' separated by spaces.
Then m lines are the operations:
op a b: 0 <= op <= 4 , 0 <= a <= b < n.
Each case has two integers in the first line: n and m (1 <= n , m <= 100000).
The next line contains n characters, '0' or '1' separated by spaces.
Then m lines are the operations:
op a b: 0 <= op <= 4 , 0 <= a <= b < n.
Output
For each output operation , output the result.
Sample Input
1 10 10 0 0 0 1 1 0 1 0 1 1 1 0 2 3 0 5 2 2 2 4 0 4 0 3 6 2 3 7 4 2 8 1 0 5 0 5 6 3 3 9
Sample Output
5 2 6 5
题意:给出0和1组成的数字串,m次操作,每次将[a,b]区间置为0或1或者将0变成1,1变成0,或者询问[a,b]内有多少个1或者最长的连续的1有多少个。
分析:
对于直接变成0,1的操作,直接区间更新就好了,对于询问,直接区间合并就好了
但是此题的关键点在于多了一个翻转操作,那么现在考虑区间合并时我们是怎么操作的,如果每次区间合并找出的是1的连续段,那么翻转时无非是把1的连续段换成了0的连续段,这样一想问题就简化了,我们只需在区间合并时同时记录最长的连续0和1,在翻转时将两者对应的值交换问题就解决了。
但是此题还不止这样。
由于有翻转操作,那么在区间更新时就有可能懒操作未执行时就已经被翻转操作覆盖从而得到错误的答案。
给个例子:
/**
数字串: 0 1 0 1
线段树:
[1,4]
/ \
[1,2] [3,4]
/ \ / \
[1] [2] [3] [4]
操作:
1 3 4
2 3 4
那么此时在区间[3,4]上的标记 1 就直接被接下来的 2 覆盖掉了
**/
对于这种情况,我们应该先执行之前的tag操作,即每次pushdown先检查2*k位置和2*k+1位置是否有标记。
PS:代码未优化,有点长。
/**
此题应注意的三个问题:
1.前置pushdowm。
2.pushdown时,如果向下传递的tag为2(翻转操作),那么应该先对子节点进行pushdown操作。
3.pushdown时应考虑该线段是否越界。
**/
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstdlib>
#include<cmath>
#include<vector>
//#pragma comment(linker, "/STACK:1024000000,1024000000");
using namespace std;
#define INF 0x3f3f3f3f
struct node
{
int l,r;
int tag;
int num1,num0;
int vl,vr;
int lt1,rt1,len1;
int lt0,rt0,len0;
} T[600000];
node Merge(node A,node B)
{
node C;
C.l=A.l,C.r=B.r;
C.tag=-1;
C.num1=A.num1+B.num1;
C.num0=A.num0+B.num0;
C.vl=A.vl,C.vr=B.vr;
C.lt1=A.lt1;
C.rt1=B.rt1;
C.len1=max(A.len1,B.len1);
if(A.vr==B.vl&&A.vr==1)
{
if(B.rt1==B.r-B.l+1) C.rt1+=A.rt1;
if(A.lt1==A.r-A.l+1) C.lt1+=B.lt1;
C.len1=max(C.len1,A.rt1+B.lt1);
}
C.len1=max(C.len1,max(C.rt1,C.lt1));
C.lt0=A.lt0;
C.rt0=B.rt0;
C.len0=max(A.len0,B.len0);
if(A.vr==B.vl&&A.vr==0)
{
if(B.rt0==B.r-B.l+1) C.rt0+=A.rt0;
if(A.lt0==A.r-A.l+1) C.lt0+=B.lt0;
C.len0=max(C.len0,A.rt0+B.lt0);
}
C.len0=max(C.len0,max(C.rt0,C.lt0));
return C;
}
void pushdown(int k)
{
if(T[k].tag==-1||T[k].l==T[k].r) return ;
if(T[k].tag==2)
{
pushdown(2*k);
pushdown(2*k+1);
}
T[2*k].tag=T[2*k+1].tag=T[k].tag;
if(T[k].tag==0)
{
T[2*k].vl=T[2*k].vr=0;
T[2*k].num1=T[2*k].lt1=T[2*k].rt1=T[2*k].len1=0;
T[2*k].num0=T[2*k].lt0=T[2*k].rt0=T[2*k].len0=T[2*k].r-T[2*k].l+1;
T[2*k+1].vl=T[2*k+1].vr=0;
T[2*k+1].num1=T[2*k+1].lt1=T[2*k+1].rt1=T[2*k+1].len1=0;
T[2*k+1].num0=T[2*k+1].lt0=T[2*k+1].rt0=T[2*k+1].len0=T[2*k+1].r-T[2*k+1].l+1;
}
else if(T[k].tag==1)
{
T[2*k].vl=T[2*k].vr=1;
T[2*k].num1=T[2*k].lt1=T[2*k].rt1=T[2*k].len1=T[2*k].r-T[2*k].l+1;
T[2*k].num0=T[2*k].lt0=T[2*k].rt0=T[2*k].len0=0;
T[2*k+1].vl=T[2*k+1].vr=1;
T[2*k+1].num1=T[2*k+1].lt1=T[2*k+1].rt1=T[2*k+1].len1=T[2*k+1].r-T[2*k+1].l+1;
T[2*k+1].num0=T[2*k+1].lt0=T[2*k+1].rt0=T[2*k+1].len0=0;
}
else if(T[k].tag==2)
{
T[2*k].vl^=1;
if(T[2*k].r!=T[2*k].l) T[2*k].vr^=1;
else T[2*k].vr=T[2*k].vl;
swap(T[2*k].num0,T[2*k].num1);
swap(T[2*k].lt0,T[2*k].lt1);
swap(T[2*k].rt0,T[2*k].rt1);
swap(T[2*k].len0,T[2*k].len1);
T[2*k+1].vl^=1;
if(T[2*k+1].r!=T[2*k+1].l) T[2*k+1].vr^=1;
else T[2*k+1].vr=T[2*k+1].vl;
swap(T[2*k+1].num0,T[2*k+1].num1);
swap(T[2*k+1].lt0,T[2*k+1].lt1);
swap(T[2*k+1].rt0,T[2*k+1].rt1);
swap(T[2*k+1].len0,T[2*k+1].len1);
}
T[k].tag=-1;
}
void init(int l,int r,int k)
{
T[k].l=l;
T[k].r=r;
T[k].tag=-1;
if(l==r)
{
int temp;
scanf("%d",&temp);
T[k].vl=T[k].vr=temp;
if(temp) T[k].num1=T[k].lt1=T[k].rt1=T[k].len1=1,T[k].num0=T[k].lt0=T[k].rt0=T[k].len0=0;
else T[k].num1=T[k].lt1=T[k].rt1=T[k].len1=0,T[k].num0=T[k].lt0=T[k].rt0=T[k].len0=1;
return ;
}
int mid=(l+r)>>1;
init(l,mid,2*k);
init(mid+1,r,2*k+1);
T[k]=Merge(T[2*k],T[2*k+1]);
}
void Insert(int d,int l,int r,int k)
{
pushdown(k);
if(T[k].l>=l&&T[k].r<=r)
{
T[k].tag=d;
if(d==0) T[k].num1=T[k].lt1=T[k].rt1=T[k].len1=0,T[k].num0=T[k].lt0=T[k].rt0=T[k].len0=T[k].r-T[k].l+1,T[k].vl=T[k].vr=0;
else if(d==1) T[k].num1=T[k].lt1=T[k].rt1=T[k].len1=T[k].r-T[k].l+1,T[k].num0=T[k].lt0=T[k].rt0=T[k].len0=0,T[k].vl=T[k].vr=1;
else if(d==2)
{
T[k].vl^=1;
if(l!=r) T[k].vr^=1;
else T[k].vr=T[k].vl;
swap(T[k].num0,T[k].num1);
swap(T[k].lt0,T[k].lt1);
swap(T[k].rt0,T[k].rt1);
swap(T[k].len0,T[k].len1);
}
return ;
}
int mid=(T[k].l+T[k].r)>>1;
if(r<=mid) Insert(d,l,r,2*k);
else if(l>mid) Insert(d,l,r,2*k+1);
else
{
Insert(d,l,mid,2*k);
Insert(d,mid+1,r,2*k+1);
}
T[k]=Merge(T[2*k],T[2*k+1]);
}
node Find(int l,int r,int k)
{
pushdown(k);
if(T[k].l>=l&&T[k].r<=r)
{
return T[k];
}
int mid=(T[k].l+T[k].r)>>1;
if(r<=mid) return Find(l,r,2*k);
else if(l>mid) return Find(l,r,2*k+1);
else return Merge(Find(l,mid,2*k),Find(mid+1,r,2*k+1));
}
int main()
{
int TAT;
scanf("%d",&TAT);
while(TAT--)
{
int n,m;
scanf("%d%d",&n,&m);
init(1,n,1);
int c=1;
while(m--)
{
int op,a,b;
scanf("%d%d%d",&op,&a,&b);
a++;
b++;
if(op<=2)
{
Insert(op,a,b,1);
}
else if(op==3)
{
node temp=Find(a,b,1);
printf("%d\n",temp.num1);
}
else if(op==4)
{
node temp=Find(a,b,1);
printf("%d\n",temp.len1);
}
}
}
return 0;
}