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

输入

复制
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%的数据,1≤n,m≤10001\le n,m \le 10001n,m1000;
对于100%的数据,1≤n,m≤1051\le n,m \le 10^51n,m105。

分析

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;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-08-10 18:11  er007  阅读(24)  评论(0编辑  收藏  举报