维护一个只有0和1的整数序列,支持以下操作:
1 x y v : 将区间[x,y]之间的所有整数都变为v(v为0或1);
2 x y : 将区间[x,y]之间所有的1变为0,所有的0变为1;
3 x y : 查询区间[x,y]内的1的个数。
线段数练习:每段保存3个关键信息:和,修改标记,反转标记。
需注意的几点:
在更新某段时,之前的反转操作将无效,应将其清零,在下传修改标记时,应将左右儿子的反转标记清零。
#include <stdio.h> #define N 100001 int n,m,ans; int a[N],sum[4*N],val[4*N],rev[4*N]; void update(int cur) { int ls=cur<<1,rs=cur<<1|1; sum[cur]=sum[ls]+sum[rs]; } void pushdown(int cur,int x,int y) { int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1; if(x==y) return; if(val[cur]!=-1) { val[ls]=val[rs]=val[cur]; sum[ls]=val[cur]*(mid-x+1); sum[rs]=val[cur]*(y-mid); val[cur]=-1; rev[ls]=rev[rs]=0; } if(rev[cur]) { rev[ls]^=1; rev[rs]^=1; sum[ls]=mid-x+1-sum[ls]; sum[rs]=y-mid-sum[rs]; rev[cur]=0; } } void build(int cur,int x,int y) { int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1; val[cur]=-1; rev[cur]=0; if(x==y) { sum[cur]=a[x]; return; } build(ls,x,mid); build(rs,mid+1,y); update(cur); } void change(int cur,int x,int y,int s,int t,int value) { int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1; if(x>=s && y<=t) { sum[cur]=(y-x+1)*value; val[cur]=value; rev[cur]=0; return; } pushdown(cur,x,y); if(mid>=s) change(ls,x,mid,s,t,value); if(mid+1<=t) change(rs,mid+1,y,s,t,value); update(cur); } void reverse(int cur,int x,int y,int s,int t) { int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1; if(x>=s && y<=t) { sum[cur]=y-x+1-sum[cur]; rev[cur]^=1; return; } pushdown(cur,x,y); if(mid>=s) reverse(ls,x,mid,s,t); if(mid+1<=t) reverse(rs,mid+1,y,s,t); update(cur); } void query(int cur,int x,int y,int s,int t) { int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1; if(x>=s && y<=t) { ans+=sum[cur]; return; } pushdown(cur,x,y); if(mid>=s) query(ls,x,mid,s,t); if(mid+1<=t) query(rs,mid+1,y,s,t); } int main() { int i,opt,x,y,z; while(~scanf("%d",&n)) { for(i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); scanf("%d",&m); while(m--) { scanf("%d%d%d",&opt,&x,&y); if(opt==3) { ans=0; query(1,1,n,x,y); printf("%d\n",ans); } else if(opt==2) reverse(1,1,n,x,y); else { scanf("%d",&z); change(1,1,n,x,y,z); } } } return 0; }