【SCOI 2010】序列操作

xiaoxiao2025-08-08  27

【题目】

传送门

题目描述:

lxhgww 最近收到了一个 01 01 01 序列,序列里面包含了 n n n 个数,这些数要么是 0 0 0,要么是 1 1 1,现在对于这个序列有五种变换操作和询问操作:

0 0 0 a a a b b b:把 [ a a a , b b b ] 区间内的所有数全变成 0 0 0

1 1 1 a a a b b b:把 [ a a a , b b b ] 区间内的所有数全变成 1 1 1

2 2 2 a a a b b b:把 [ a a a , b b b ] 区间内的所有数全部取反,也就是说把所有的 0 0 0 变成 1 1 1,把所有的 1 1 1 变成 0 0 0

3 3 3 a a a b b b:询问 [ a a a , b b b ] 区间内总共有多少个 1 1 1

4 4 4 a a a b b b:询问 [ a a a , b b b ] 区间内最多有多少个连续的 1 1 1

对于每一种询问操作,lxhgww 都需要给出回答,聪明的程序员们,你们能帮助他吗?

输入格式:

输入数据第一行包括 2 2 2 个数, n n n m m m,分别表示序列的长度和操作数目

第二行包括 n n n 个数,表示序列的初始状态

接下来 m m m 行,每行 3 3 3 个数, o p , a , b op, a, b op,a,b,( 0 0 0 o p op op 4 4 4 0 0 0 a a a b b b < n n n)表示对于区间 [ a a a , b b b ] 执行标号为 o p op op 的操作

输出格式:

对于每一个询问操作,输出一行,包括 1 1 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

输出 5 2 6 5

说明:

【数据范围】 对于 30 % 30\% 30% 的数据, 1 1 1 n , m n, m n,m 1000 1000 1000 对于 100 % 100\% 100% 的数据, 1 1 1 n , m n, m n,m 100000 100000 100000

【分析】

题解:线段树,支持区间覆盖,区间取反,区间求和,区间求最大连续子段

其实这几个操作都是基础的操作,但由于代码能力较弱,硬是调了很久

应该算是一道好题吧,比较综合,把很多东西都一次就考到了

代码还是比较简洁,不算很长,但还是有很多细节

【代码】

#include<cstdio> #include<cstring> #include<algorithm> #define N 100005 using namespace std; int a[N]; struct node { int L[2],R[2],Max[2],sum[2],len,change,cover; }Seg[N<<2]; node update(node left,node right) { node root; root.change=0,root.cover=-1; root.len=left.len+right.len; for(int i=0;i<=1;++i) { root.sum[i]=left.sum[i]+right.sum[i]; root.L[i]=(left.L[i]==left.len?left.L[i]+right.L[i]:left.L[i]); root.R[i]=(right.R[i]==right.len?right.R[i]+left.R[i]:right.R[i]); root.Max[i]=max(max(left.Max[i],right.Max[i]),left.R[i]+right.L[i]); } return root; } void Build(int root,int l,int r) { if(l==r) { Seg[root].change=0,Seg[root].cover=-1,Seg[root].len=1; Seg[root].L[a[l]]=Seg[root].R[a[l]]=Seg[root].Max[a[l]]=Seg[root].sum[a[l]]=1; return; } int mid=(l+r)>>1; Build(root<<1,l,mid); Build(root<<1|1,mid+1,r); Seg[root]=update(Seg[root<<1],Seg[root<<1|1]); } void Cover(int root,int l,int r,int val) { Seg[root].cover=val;Seg[root].change=0; Seg[root].L[val]=Seg[root].R[val]=Seg[root].Max[val]=Seg[root].sum[val]=r-l+1; Seg[root].L[val^1]=Seg[root].R[val^1]=Seg[root].Max[val^1]=Seg[root].sum[val^1]=0; } void Change(int root) { Seg[root].change^=1; swap(Seg[root].L[0],Seg[root].L[1]); swap(Seg[root].R[0],Seg[root].R[1]); swap(Seg[root].sum[0],Seg[root].sum[1]); swap(Seg[root].Max[0],Seg[root].Max[1]); } void Pushdown(int root,int l,int r,int mid) { if(Seg[root].cover!=-1) Cover(root<<1,l,mid,Seg[root].cover),Cover(root<<1|1,mid+1,r,Seg[root].cover); if(Seg[root].change) Change(root<<1),Change(root<<1|1); Seg[root].cover=-1,Seg[root].change=0; } void Modify(int root,int l,int r,int x,int y,int k) { if(l>=x&&r<=y) { Cover(root,l,r,k); return; } int mid=(l+r)>>1; Pushdown(root,l,r,mid); if(x<=mid) Modify(root<<1,l,mid,x,y,k); if(y>mid) Modify(root<<1|1,mid+1,r,x,y,k); Seg[root]=update(Seg[root<<1],Seg[root<<1|1]); } void Negate(int root,int l,int r,int x,int y) { if(l>=x&&r<=y) { Change(root); return; } int mid=(l+r)>>1; Pushdown(root,l,r,mid); if(x<=mid) Negate(root<<1,l,mid,x,y); if(y>mid) Negate(root<<1|1,mid+1,r,x,y); Seg[root]=update(Seg[root<<1],Seg[root<<1|1]); } node Query(int root,int l,int r,int x,int y) { if(l>=x&&r<=y) return Seg[root]; int mid=(l+r)>>1; Pushdown(root,l,r,mid); if(y<=mid) return Query(root<<1,l,mid,x,y); if(x>mid) return Query(root<<1|1,mid+1,r,x,y); return update(Query(root<<1,l,mid,x,y),Query(root<<1|1,mid+1,r,x,y)); } int main() { int n,m,i,s,x,y; scanf("%d%d",&n,&m); for(i=1;i<=n;++i) scanf("%d",&a[i]); Build(1,1,n); for(i=1;i<=m;++i) { scanf("%d%d%d",&s,&x,&y);x++,y++; if(s==0) Modify(1,1,n,x,y,0); if(s==1) Modify(1,1,n,x,y,1); if(s==2) Negate(1,1,n,x,y); if(s==3) printf("%d\n",Query(1,1,n,x,y).sum[1]); if(s==4) printf("%d\n",Query(1,1,n,x,y).Max[1]); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-5034481.html

最新回复(0)