1021 [SCOI2010]序列操作 区间最大连续1的数量 lazy标记 全1 全0 翻转
链接:https://ac.nowcoder.com/acm/contest/26896/1021
来源:牛客网
题目描述
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)
输出描述:
对于每一个询问操作,输出一行,包括1个数,表示其对应的答案
示例1
备注:
对于30%的数据,1≤n,m≤10001\le n,m \le 10001≤n,m≤1000;
对于100%的数据,1≤n,m≤1051\le n,m \le 10^51≤n,m≤105。
分析
lazy表示这个区间要翻转还是全1或全0或者不操作
关键是连续1 的数量,如果根区间最大连续1的数量是 左区间和右区间最大数量的最大值,或者左区间的右边连续1的数量 + 右区间左边连续1的数量
当询问连续1的数量时,由于要统计左边1的数量和右边1的数量,所以子节点要形成真正的节点完完全全的传回来让根节点累加
//-------------------------代码---------------------------- //#define int ll const int N = 1e5+10; int n,m; #define root tr[u] #define lt tr[ul] #define rh tr[ur] struct node { int l,r,la,cnt[2],z[2],y[2],mx[2]; //左边界 右边界 lazy标记 总数 左边总数 右边总数 最大连续1的数量 } tr[N <<2]; int a[N]; void push_up(int u) { for(int i=0;i<2;i++) { tr[u].cnt[i]=tr[ul].cnt[i]+tr[ur].cnt[i]; tr[u].mx[i]=max(tr[ul].y[i]+tr[ur].z[i],max(tr[ul].mx[i],tr[ur].mx[i])); tr[u].z[i]=tr[ul].z[i]; tr[u].y[i]=tr[ur].y[i]; if(tr[u].z[i]==tr_len(ul))tr[u].z[i]+=tr[ur].z[i]; if(tr[u].y[i]==tr_len(ur))tr[u].y[i]+=tr[ul].y[i]; } } void change(int u) { swap(tr[u].cnt[0],tr[u].cnt[1]); swap(tr[u].mx[0],tr[u].mx[1]); swap(tr[u].z[0],tr[u].z[1]); swap(tr[u].y[0],tr[u].y[1]); if(tr[u].la==2)tr[u].la=-1; else if(tr[u].la==-1)tr[u].la=2; else tr[u].la^=1; } void push_down(int u) { if(tr[u].la==-1)return ; if(tr[u].la==2) { change(ul); change(ur); } else { int x=tr[u].la; tr[ul].la=tr[ur].la=x; tr[ul].cnt[x]=tr[ul].mx[x]=tr[ul].z[x]=tr[ul].y[x]=tr_len(ul); tr[ul].cnt[x^1]=tr[ul].mx[x^1]=tr[ul].z[x^1]=tr[ul].y[x^1]=0; tr[ur].cnt[x]=tr[ur].mx[x]=tr[ur].z[x]=tr[ur].y[x]=tr_len(ur); tr[ur].cnt[x^1]=tr[ur].mx[x^1]=tr[ur].z[x^1]=tr[ur].y[x^1]=0; } tr[u].la=-1; } void build(int u,int l,int r) { tr[u] = {l,r,-1}; if(l == r) { root.cnt[a[l]] = root.z[a[l]] = root.y[a[l]] = root.mx[a[l]] = 1; root.cnt[a[l]^1] = root.z[a[l] ^ 1] = root.y[a[l]^1] = root.mx[a[l]^1] = 0; rt; } build(ul,l,tr_mid);build(ur,tr_mid+1,r); push_up(u); } void modify(int u,int l,int r,int x) { if(l <= root.l && root.r <= r) { if(x == 2) change(u); else { root.la = x; root.cnt[x] = root.mx[x] = root.z[x] = root.y[x] = (root.r - root.l + 1); root.cnt[x^1] = root.mx[x^1] = root.z[x^1] = root.y[x^1] = 0; } rt; } push_down(u);if(l<=tr_mid)modify(ul,l,r,x);if(tr_mid < r)modify(ur,l,r,x);push_up(u); } int query1(int u,int l,int r) { if(root.l >= l && root.r <= r) return root.cnt[1]; if(root.l > r || root.r < l) return 0; push_down(u); return query1(ul,l,r) + query1(ur,l,r); } node query2(int u,int l,int r) { if(tr[u].l>=l&&tr[u].r<=r)return tr[u]; push_down(u); if(r<=tr_mid)return query2(ul,l,r); if(l>tr_mid)return query2(ur,l,r); node tmp1=query2(ul,l,r),tmp2=query2(ur,l,r); tmp1.mx[1]=max(tmp1.y[1]+tmp2.z[1],max(tmp1.mx[1],tmp2.mx[1])); tmp1.cnt[1]+=tmp2.cnt[1]; if(tmp1.z[1]==(tmp1.r-tmp1.l+1))tmp1.z[1]+=tmp2.z[1]; if(tmp2.y[1]==(tmp2.r-tmp2.l+1))tmp1.y[1]=tmp1.y[1]+tmp2.y[1]; else tmp1.y[1]=tmp2.y[1]; return tmp1; } void solve() { cin>>n>>m; fo(i,1,n) cin>>a[i]; build(1,1,n); while(m -- ) { int op,l,r;cin>>op>>l>>r;l++,r++; if(op <= 2) modify(1,l,r,op); if(op == 3) cout<<query1(1,l,r)<<endl; if(op == 4) cout<<query2(1,l,r).mx[1]<<endl; } } // 5 // 2 // 6 // 5 // 5 // 2 // 6 // 5 void main_init() {} signed main(){ AC();clapping();TLE; cout<<fixed<<setprecision(12); main_init(); // while(cin>>n,n) // while(cin>>n>>m,n,m) // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------