1858: [Scoi2010]序列操作
Time Limit: 10 Sec Memory Limit: 64 MB
Description
lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 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 对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?
Input
输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目 第二行包括n个数,表示序列的初始状态 接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<=""div="" style="font-family: arial, verdana, helvetica,sans-serif;">
Output
对于每一个询问操作,输出一行,包括1个数,表示其对应的答案
Sample Input
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
HINT
对于30%的数据,1<=n, m<=1000
对于100%的数据,1<=n, m<=100000
题目分析:hotel那题的加强版。在这里我们不仅要维护最长连续的1,还要维护0,因为它随时可能取反。还有一点要比较注意的是各种懒惰标记之间的覆盖与合并问题,比如一个点原先有op=0的懒惰标记(将子树全部变为0),再在它上面下传一个op=2的懒惰标记(将子树全部取反),结果等于一个op=1的懒惰标记(全部变为1),之类的……
CODE:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=100100;
struct data
{
int llen,rlen,slen;
} ;
struct Tnode
{
int add;
data num[2];
int sum;
} tree[maxn<<2];
int a[maxn];
int n,m;
void Clear(int root,int L,int R,int x)
{
Tnode *P=tree+root;
P->sum=(R-L+1)*x;
P->num[x].llen=R-L+1;
P->num[x].rlen=R-L+1;
P->num[x].slen=R-L+1;
P->num[!x].llen=0;
P->num[!x].rlen=0;
P->num[!x].slen=0;
}
void Work(int root,int L,int R,int id)
{
int left=root<<1;
int right=left|1;
int mid=(L+R)>>1;
int temp=tree[left].num[id].llen;
tree[root].num[id].llen=temp;
if ( temp==mid-L+1 ) tree[root].num[id].llen+=tree[right].num[id].llen;
temp=tree[right].num[id].rlen;
tree[root].num[id].rlen=temp;
if ( temp==R-mid ) tree[root].num[id].rlen+=tree[left].num[id].rlen;
temp=max( tree[left].num[id].slen,tree[right].num[id].slen );
temp=max( temp,tree[left].num[id].rlen+tree[right].num[id].llen );
tree[root].num[id].slen=temp;
}
void Up(int root,int L,int R)
{
int left=root<<1;
int right=left|1;
tree[root].sum=tree[left].sum+tree[right].sum;
Work(root,L,R,0);
Work(root,L,R,1);
}
void Build(int root,int L,int R)
{
tree[root].add=0;
if (L==R)
{
Clear(root,L,R,a[L]);
return;
}
int left=root<<1;
int right=left|1;
int mid=(L+R)>>1;
Build(left,L,mid);
Build(right,mid+1,R);
Up(root,L,R);
}
void Change(int root,int L,int R,int op)
{
if (op==1)
{
Clear(root,L,R,0);
tree[root].add=op;
}
if (op==2)
{
Clear(root,L,R,1);
tree[root].add=op;
}
if (op==3)
{
swap(tree[root].num[0],tree[root].num[1]);
tree[root].sum=(R-L+1)-tree[root].sum;
if (tree[root].add==1) tree[root].add++;
else if (tree[root].add==2) tree[root].add--;
else if (tree[root].add==3) tree[root].add=0;
else tree[root].add=3;
}
}
void Down(int root,int L,int R)
{
if (!tree[root].add) return;
int left=root<<1;
int right=left|1;
int mid=(L+R)>>1;
Change(left,L,mid,tree[root].add);
Change(right,mid+1,R,tree[root].add);
tree[root].add=0;
}
void Update(int root,int L,int R,int x,int y,int op)
{
if ( y>1;
Update(left,L,mid,x,y,op);
Update(right,mid+1,R,x,y,op);
Up(root,L,R);
}
int Query(int root,int L,int R,int x,int y,int op)
{
if ( y>1;
int vl=Query(left,L,mid,x,y,op);
int vr=Query(right,mid+1,R,x,y,op);
if (op==4) return vl+vr;
else
{
int temp=max(vl,vr);
int tl=max(x,mid-tree[left].num[1].rlen+1);
int tr=min(y,mid+tree[right].num[1].llen);
temp=max(temp,tr-tl+1);
return temp;
}
}
int main()
{
freopen("bzoj1858.in","r",stdin);
freopen("bzoj1858.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++) scanf("%d",&a[i]);
Build(1,1,n);
/*for (int i=1; i<=30; i++)
{
cout<add<<' ';
cout<sum<<' ';
cout<num[0].llen<<' ';
cout<num[0].rlen<<' ';
cout<num[0].slen<<' ';
cout<num[1].llen<<' ';
cout<num[1].rlen<<' ';
cout<num[1].slen<<' ';
cout<