题目描述
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都需要给出回答,聪明的程序员们,你们能帮助他吗?
输入输出格式
输入格式:
输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目
第二行包括n个数,表示序列的初始状态
接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<n)表示对于区间[a, b]执行标号为op的操作
输出格式:
对于每一个询问操作,输出一行,包括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
题目描述
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都需要给出回答,聪明的程序员们,你们能帮助他吗?
输入输出格式
输入格式:
输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目
第二行包括n个数,表示序列的初始状态
接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<n)表示对于区间[a, b]执行标号为op的操作
输出格式:
对于每一个询问操作,输出一行,包括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
这些操作都比较简单 之前都学过
但是加在一起就会产生一个问题 那就是翻转标记和区间修改标记的顺序该如何处理 先反转和先修改的操作是不一样的
修改操作的优先级是比翻转操作的优先级高的
在update里
对一个点先后两次操作一共有四种方法
1.先反转后修改
显然 翻转的操作已经被覆盖掉了 所以在设置修改懒标记的时候如果有翻转标记直接清空掉
2.先修改后翻转
正常处理
3.4没有问题
在down里
先处理修改的 因为修改的优先级高(先反转后修改的操作已经被覆盖掉了 也就是反转标记已经被清零)
下推懒标记的时候如果下面的两个儿子有翻转标记的话要清空
然后处理翻转标记即可
非常好的线段树 加深了理解
#include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define pb push_back #define inf 0x3f3f3f3f #define lson l,m,pos<<1 #define rson m+1,r,pos<<1|1 #define CLR(A,v) memset(A,v,sizeof A) typedef pair<int,int>pii; ////////////////////////////////// const int N=1e5+10; int tsum[N<<2],t0[N<<2],t1[N<<2],ri0[N<<2],ri1[N<<2],le0[N<<2],le1[N<<2],len[N<<2],col[N<<2],rev[N<<2]; int num[N]; void up(int pos) { tsum[pos]=tsum[pos<<1]+tsum[pos<<1|1];// 区间求和 t0[pos]=max( max(t0[pos<<1],t0[pos<<1|1]),ri0[pos<<1]+le0[pos<<1|1] ); t1[pos]=max( max(t1[pos<<1],t1[pos<<1|1]),ri1[pos<<1]+le1[pos<<1|1] ); if(le1[pos<<1]==len[pos<<1]) le1[pos]=le1[pos<<1]+le1[pos<<1|1]; else le1[pos]=le1[pos<<1]; if(le0[pos<<1]==len[pos<<1]) le0[pos]=le0[pos<<1]+le0[pos<<1|1]; else le0[pos]=le0[pos<<1]; if(ri1[pos<<1|1]==len[pos<<1|1]) ri1[pos]=ri1[pos<<1|1]+ri1[pos<<1]; else ri1[pos]=ri1[pos<<1|1]; if(ri0[pos<<1|1]==len[pos<<1|1]) ri0[pos]=ri0[pos<<1|1]+ri0[pos<<1]; else ri0[pos]=ri0[pos<<1|1]; } void build(int l,int r,int pos) { len[pos]=r-l+1; if(l==r){ tsum[pos]=num[l]; le0[pos]=ri0[pos]=t0[pos]=(num[l]==0); le1[pos]=ri1[pos]=t1[pos]=(num[l]==1); return ;} int m=(l+r)>>1;build(lson);build(rson);up(pos); } void down(int m,int pos) { if(col[pos]!=-1)// 修改会覆盖翻转 { rev[pos<<1]=rev[pos<<1|1]=0;//覆盖翻转 col[pos<<1]=col[pos<<1|1]=col[pos];//标记传递 if(col[pos]==1){ t1[pos<<1]=tsum[pos<<1]=le1[pos<<1]=ri1[pos<<1]=len[pos<<1]; t1[pos<<1|1]=tsum[pos<<1|1]=le1[pos<<1|1]=ri1[pos<<1|1]=len[pos<<1|1]; t0[pos<<1]=t0[pos<<1|1]=le0[pos<<1]=le0[pos<<1|1]=ri0[pos<<1]=ri0[pos<<1|1]=0;} else if(col[pos]==0){ t0[pos<<1]=le0[pos<<1]=ri0[pos<<1]=len[pos<<1]; t0[pos<<1|1]=le0[pos<<1|1]=ri0[pos<<1|1]=len[pos<<1|1]; tsum[pos<<1]=tsum[pos<<1|1]=le1[pos<<1]=le1[pos<<1|1]=ri1[pos<<1]=ri1[pos<<1|1]=t1[pos<<1]=t1[pos<<1|1]=0;} col[pos]=-1; } if(rev[pos]) { tsum[pos<<1]=len[pos<<1]-tsum[pos<<1]; tsum[pos<<1|1]=len[pos<<1|1]-tsum[pos<<1|1]; swap(le1[pos<<1],le0[pos<<1]); swap(le1[pos<<1|1],le0[pos<<1|1]); swap(ri1[pos<<1],ri0[pos<<1]); swap(ri1[pos<<1|1],ri0[pos<<1|1]); swap(t1[pos<<1],t0[pos<<1]); swap(t1[pos<<1|1],t0[pos<<1|1]);//翻转01最大连续长度 rev[pos<<1]^=1;rev[pos<<1|1]^=1; rev[pos]=0; } } void upsum(int L,int R,int v,int l,int r,int pos) { if(L<=l&&r<=R) { col[pos]=v;rev[pos]=0;tsum[pos]=v*(r-l+1); t1[pos]=le1[pos]=ri1[pos]=v*(r-l+1); t0[pos]=le0[pos]=ri0[pos]=(v^1)*(r-l+1); return ; }int m=(l+r)>>1;down(r-l+1,pos); if(L<=m)upsum(L,R,v,lson);if(R>m)upsum(L,R,v,rson);up(pos); } void uprev(int L,int R,int l,int r,int pos) { if(L<=l&&r<=R) { rev[pos]^=1; tsum[pos]=r-l+1-tsum[pos]; swap(t1[pos],t0[pos]); swap(le1[pos],le0[pos]); swap(ri1[pos],ri0[pos]); return ; }int m=(l+r)>>1;down(r-l+1,pos); if(L<=m)uprev(L,R,lson);if(R>m)uprev(L,R,rson);up(pos); } int qsum(int L,int R,int l,int r,int pos) { if(L<=l&&r<=R)return tsum[pos]; int ans=0;int m=(l+r)>>1;down(r-l+1,pos); if(L<=m)ans+=qsum(L,R,lson);if(R>m)ans+=qsum(L,R,rson); return ans; } int qmax(int L,int R,int l,int r,int pos) { if(L<=l&&r<=R)return t1[pos]; int m=(l+r)>>1; down(r-l+1,pos); if(L<=m&&R>m) { int ans=max(qmax(L,R,lson),qmax(L,R,rson)),rm,lm; rm=min((m-L+1),ri1[pos<<1] ); lm=min((R-m),le1[pos<<1|1]); ans=max(ans,rm+lm);return ans; } else if(L<=m)return qmax(L,R,lson); else if(R>m)return qmax(L,R,rson); } int n,m,a,b,c; int main() { CLR(col,-1); RII(n,m); rep(i,1,n)RI(num[i]); build(1,n,1); while(m--) { RIII(c,a,b);a++,b++; if(c==0)upsum(a,b,0,1,n,1); if(c==1)upsum(a,b,1,1,n,1); if(c==2)uprev(a,b,1,n,1); if(c==3)printf("%d ",qsum(a,b,1,n,1)); if(c==4)printf("%d ",qmax(a,b,1,n,1)); } return 0; }
0 5 6 3 3 9
5 2 6 5