版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/81605874
Sequence operation
题意: HDU - 3911 的升级版;
给出一个01串,5种操作:
0 L R:区间[L ,R]全置为0;
1 L R:区间[L, R]全置为1;
2 L R :区间[L, R]中0变1,1变0;
3 L R:求区间[L, R]中1的总个数;
4 L R:求区间[L, R]中连续1的最长长度;
可以先看HDU-3911的题解,更容易理解一些:HDU-3911题解
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct node{
int l, r, len;//l, r表示区间范围, len表示区间长度;
int l_one, l_zero, r_one, r_zero;//l_表示由l开始向右连续的1或0(称之为左连续), r_表示由r开始向左连续的1或0(称之为右连续);
int m_one, m_zero, n_one, n_zero;//m_表示区间内最长的连续的1或0(称之为最大连续), n_表示区间内1或0的个数;
int lazy0, lazy1, lazy2;//lazy0表示0操作(全置为0), lazy1表示1操作(全置为1), lazy2表示2操作(0变1, 1变0);
}tr[maxn<<2];
void pushup(int m){
//1, 0的总个数就是左右孩子相加;
tr[m].n_one=tr[m<<1].n_one+tr[m<<1|1].n_one;
tr[m].n_zero=tr[m<<1].n_zero+tr[m<<1|1].n_zero;
//如果左孩子的左连续等于左孩子区间大小, 那么左孩子的左连续就可以和右孩子的左连续合并;
tr[m].l_one=tr[m<<1].l_one;
if(tr[m<<1].l_one==tr[m<<1].len) tr[m].l_one+=tr[m<<1|1].l_one;
tr[m].l_zero=tr[m<<1].l_zero;
if(tr[m<<1].l_zero==tr[m<<1].len) tr[m].l_zero+=tr[m<<1|1].l_zero;
//如果右孩子的右连续等于右孩子区间大小, 那么右孩子的右连续就可以和左孩子的右连续合并;
tr[m].r_one=tr[m<<1|1].r_one;
if(tr[m<<1|1].r_one==tr[m<<1|1].len) tr[m].r_one+=tr[m<<1].r_one;
tr[m].r_zero=tr[m<<1|1].r_zero;
if(tr[m<<1|1].r_zero==tr[m<<1|1].len) tr[m].r_zero+=tr[m<<1].r_zero;
//1, 0的最大连续是左右孩子最大连续中的最大值,最后再将左孩子的右连续与右孩子的左连续合并, 比较;
tr[m].m_one=max(max(tr[m<<1].m_one, tr[m<<1|1].m_one), tr[m<<1].r_one+tr[m<<1|1].l_one);
tr[m].m_zero=max(max(tr[m<<1].m_zero, tr[m<<1|1].m_zero), tr[m<<1].r_zero+tr[m<<1|1].l_zero);
}
//0操作:
void pushdown0(int m){
if(tr[m].lazy0){
tr[m<<1].lazy0=tr[m<<1|1].lazy0=1;
tr[m<<1].lazy1=tr[m<<1].lazy2=tr[m<<1|1].lazy1=tr[m<<1|1].lazy2=0;
tr[m<<1].n_one=tr[m<<1|1].n_one=0;
tr[m<<1].n_zero=tr[m<<1].len;
tr[m<<1|1].n_zero=tr[m<<1|1].len;
tr[m<<1].m_one=tr[m<<1|1].m_one=0;
tr[m<<1].m_zero=tr[m<<1].len;
tr[m<<1|1].m_zero=tr[m<<1|1].len;
tr[m<<1].l_one=tr[m<<1].r_one=tr[m<<1|1].l_one=tr[m<<1|1].r_one=0;
tr[m<<1].l_zero=tr[m<<1].r_zero=tr[m<<1].len;
tr[m<<1|1].l_zero=tr[m<<1|1].r_zero=tr[m<<1|1].len;
tr[m].lazy0=0;
}
}
//1操作:
void pushdown1(int m){
if(tr[m].lazy1){
tr[m<<1].lazy1=tr[m<<1|1].lazy1=1;
tr[m<<1].lazy0=tr[m<<1].lazy2=tr[m<<1|1].lazy0=tr[m<<1|1].lazy2=0;
tr[m<<1].n_zero=tr[m<<1|1].n_zero=0;
tr[m<<1].n_one=tr[m<<1].len;
tr[m<<1|1].n_one=tr[m<<1|1].len;
tr[m<<1].m_zero=tr[m<<1|1].m_zero=0;
tr[m<<1].m_one=tr[m<<1].len;
tr[m<<1|1].m_one=tr[m<<1|1].len;
tr[m<<1].l_zero=tr[m<<1].r_zero=tr[m<<1|1].l_zero=tr[m<<1|1].r_zero=0;
tr[m<<1].l_one=tr[m<<1].r_one=tr[m<<1].len;
tr[m<<1|1].l_one=tr[m<<1|1].r_one=tr[m<<1|1].len;
tr[m].lazy1=0;
}
}
//2操作:
void pushdown2(int m){
if(tr[m].lazy2){
tr[m<<1].lazy2^=1;
tr[m<<1|1].lazy2^=1;
swap(tr[m<<1].l_one, tr[m<<1].l_zero);
swap(tr[m<<1].r_one, tr[m<<1].r_zero);
swap(tr[m<<1].m_one, tr[m<<1].m_zero);
swap(tr[m<<1].n_one, tr[m<<1].n_zero);
swap(tr[m<<1|1].l_one, tr[m<<1|1].l_zero);
swap(tr[m<<1|1].r_one, tr[m<<1|1].r_zero);
swap(tr[m<<1|1].m_one, tr[m<<1|1].m_zero);
swap(tr[m<<1|1].n_one, tr[m<<1|1].n_zero);
tr[m].lazy2=0;
}
}
void build(int m, int l, int r){
tr[m].l=l;
tr[m].r=r;
tr[m].lazy0=tr[m].lazy1=tr[m].lazy2=0;
tr[m].len=r-l+1;
if(l==r){
int x;
scanf("%d", &x);
if(x){
tr[m].l_one=tr[m].r_one=tr[m].m_one=tr[m].n_one=1;
tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=tr[m].n_zero=0;
}
else{
tr[m].l_one=tr[m].r_one=tr[m].m_one=tr[m].n_one=0;
tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=tr[m].n_zero=1;
}
return;
}
int mid=(l+r)>>1;
build(m<<1, l, mid);
build(m<<1|1, mid+1, r);
pushup(m);
}
void updata(int m, int l, int r, int op){
if(tr[m].l==l&&tr[m].r==r){
if(op==2){
tr[m].lazy2^=1;
//如果是2操作, 就先更新孩子节点;
pushdown0(m);
pushdown1(m);
swap(tr[m].l_one, tr[m].l_zero);
swap(tr[m].r_one, tr[m].r_zero);
swap(tr[m].m_one, tr[m].m_zero);
swap(tr[m].n_one, tr[m].n_zero);
}
else if(op==0){
tr[m].l_one=tr[m].r_one=tr[m].n_one=tr[m].m_one=0;
tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=tr[m].n_zero=tr[m].len;
tr[m].lazy0=1;
tr[m].lazy1=tr[m].lazy2=0;
}
else{
tr[m].l_one=tr[m].r_one=tr[m].n_one=tr[m].m_one=tr[m].len;
tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=tr[m].n_zero=0;
tr[m].lazy1=1;
tr[m].lazy0=tr[m].lazy2=0;
}
return;
}
pushdown0(m);
pushdown1(m);
pushdown2(m);
int mid=(tr[m].l+tr[m].r)>>1;
if(r<=mid) updata(m<<1, l, r, op);
else if(l>mid) updata(m<<1|1, l, r, op);
else{
updata(m<<1, l, mid, op);
updata(m<<1|1, mid+1, r, op);
}
pushup(m);
}
int query_m(int m, int l, int r){
if(tr[m].l==l&&tr[m].r==r){
return tr[m].m_one;
}
pushdown0(m);
pushdown1(m);
pushdown2(m);
int mid=(tr[m].l+tr[m].r)>>1;
int temp;
if(r<=mid) temp=query_m(m<<1, l, r);
else if(l>mid) temp=query_m(m<<1|1, l, r);
else{
int lmax=query_m(m<<1, l, mid);
int rmax=query_m(m<<1|1, mid+1, r);
int mm=min(tr[m<<1].r_one, mid-l+1)+min(tr[m<<1|1].l_one, r-mid);
temp=max(max(lmax, rmax), mm);
}
pushup(m);
return temp;
}
int query_n(int m, int l, int r){
if(tr[m].l==l&&tr[m].r==r){
return tr[m].n_one;
}
pushdown0(m);
pushdown1(m);
pushdown2(m);
int mid=(tr[m].l+tr[m].r)>>1;
int temp;
if(r<=mid) temp=query_n(m<<1, l, r);
else if(l>mid) temp=query_n(m<<1|1, l, r);
else temp=query_n(m<<1, l, mid)+query_n(m<<1|1, mid+1, r);
pushup(m);
return temp;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
int n, m, op, l, r;
scanf("%d%d", &n, &m);
build(1, 1, n);
while(m--){
scanf("%d%d%d", &op, &l, &r);
l++, r++;
if(op==0) updata(1, l, r, 0);
else if(op==1) updata(1, l, r, 1);
else if(op==2) updata(1, l, r, 2);
else if(op==3) printf("%d\n", query_n(1, l, r));
else printf("%d\n", query_m(1, l, r));
}
}
return 0;
}