Luogu2572 [SCOI2010]序列操作

原题链接:https://www.luogu.com.cn/problem/P2572

序列操作

题目描述

lxhgww 最近收到了一个 01 01 01 序列,序列里面包含了 n n n 个数,下标从 0 0 0 开始。这些数要么是 0 0 0,要么是 1 1 1,现在对于这个序列有五种变换操作和询问操作:

0 l r [ l , r ] [l, r] [l,r] 区间内的所有数全变成 0 0 0

1 l r [ l , r ] [l, r] [l,r] 区间内的所有数全变成 1 1 1

2 l r [ l , r ] [l,r] [l,r] 区间内的所有数全部取反,也就是说把所有的 0 0 0 变成 1 1 1,把所有的 1 1 1 变成 0 0 0

3 l r 询问 [ l , r ] [l, r] [l,r] 区间内总共有多少个 1 1 1

4 l r 询问 [ l , r ] [l, r] [l,r] 区间内最多有多少个连续的 1 1 1

对于每一种询问操作,lxhgww 都需要给出回答,聪明的程序员们,你们能帮助他吗?

输入格式

第一行两个正整数 n , m n,m n,m,表示序列长度与操作个数。
第二行包括 n n n 个数,表示序列的初始状态。
接下来 m m m 行,每行三个整数,表示一次操作。

输出格式

对于每一个询问操作,输出一行一个数,表示其对应的答案。

输入输出样例

输入 #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
输出 #1
5
2
6
5

说明/提示

【数据范围】
对于 30 % 30\% 30% 的数据, 1 ≤ n , m ≤ 1000 1\le n,m \le 1000 1n,m1000
对于 100 % 100\% 100% 的数据, 1 ≤ n , m ≤ 1 0 5 1\le n,m \le 10^5 1n,m105

题解

上一题的升级版,因为区间取反操作的存在,我们必须同时记录 0 0 0 1 1 1的包含左端点最长序列、包含右端点最长序列和整个区间最长序列,维护类似。又因为要求区间内 1 1 1的数量,所以还要维护一个区间和。

相较于上一道题,本题多了区间取反标记。因为区间赋值时,之前的区间取反标记无意义;而区间取反时,区间赋值标记还会相应取反,所以在打标记的时候,区间取反标记一定是在区间赋值标记后传下来的,即在取反标记传入的时候赋值标记已经对应的改变了。所以在下传标记的时候,要先传取反标记,再传赋值标记(举例:区间赋 0 0 0之后再区间取反相当于区间赋 1 1 1,这时候虽然节点里有两个标记,但是区间取反标记已经没意义里,所以我们下传的时候需要先下传取反标记,再传赋值标记直接覆盖掉取反标记)。

其实还有一种更好理解的写法:打取反标记的时候不改变赋值标记,下传的时候直接按照原本的“先赋值,再取反”标记顺序下传。当然也可以在传取反标记的时候检查一下该节点有无赋值标记,有则修改赋值标记(相当于合并了赋值标记和取反标记),总之写法很多,自己能理解就好。

对照代码更好理解。

代码

第一种写法:

#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=1e5+5;
struct node{
    
    
    int le,ri,llen[2],rlen[2],mlen[2],sum;
    bool clear,fill,rev;
}tree[M<<2];
int n,m,que[M];
void up(int v,int p)
{
    
    
    tree[v].llen[p]=(tree[ls].llen[p]==tree[ls].ri-tree[ls].le+1)?tree[ls].llen[p]+tree[rs].llen[p]:tree[ls].llen[p];
    tree[v].rlen[p]=(tree[rs].rlen[p]==tree[rs].ri-tree[rs].le+1)?tree[rs].rlen[p]+tree[ls].rlen[p]:tree[rs].rlen[p];
    tree[v].mlen[p]=max(tree[ls].rlen[p]+tree[rs].llen[p],max(tree[ls].mlen[p],tree[rs].mlen[p]));
}
void up(int v)
{
    
    
    up(v,0),up(v,1);
    tree[v].sum=tree[ls].sum+tree[rs].sum;
}
void push_fill(int v,int p)
{
    
    
    tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=tree[v].ri-tree[v].le+1;
}
void push_clear(int v,int p)
{
    
    
    tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=0;
}
void push_rev(int v)
{
    
    
    swap(tree[v].llen[0],tree[v].llen[1]);
    swap(tree[v].rlen[0],tree[v].rlen[1]);
    swap(tree[v].mlen[0],tree[v].mlen[1]);
    tree[v].sum=tree[v].ri-tree[v].le+1-tree[v].sum;
    tree[v].rev^=1;
    if(tree[v].fill||tree[v].clear)swap(tree[v].fill,tree[v].clear);
}
void down(int v)
{
    
    
    if(tree[v].rev)
    {
    
    
        push_rev(ls),push_rev(rs);
        tree[v].rev=0;
    }
    if(tree[v].clear)
    {
    
    
        push_clear(ls,1),push_fill(ls,0);
        push_clear(rs,1),push_fill(rs,0);
        tree[ls].clear=1,tree[ls].fill=tree[ls].rev=0;
        tree[rs].clear=1,tree[rs].fill=tree[rs].rev=0;
        tree[ls].sum=tree[rs].sum=0;
        tree[v].clear=0;
    }
    if(tree[v].fill)
    {
    
    
        push_clear(ls,0),push_fill(ls,1);
        push_clear(rs,0),push_fill(rs,1);
        tree[ls].fill=1,tree[ls].clear=tree[ls].rev=0;
        tree[rs].fill=1,tree[rs].clear=tree[rs].rev=0;
        tree[ls].sum=tree[ls].ri-tree[ls].le+1;
        tree[rs].sum=tree[rs].ri-tree[rs].le+1;
        tree[v].fill=0;
    }
}
void build(int v,int le,int ri)
{
    
    
    tree[v].le=le,tree[v].ri=ri;
    if(le==ri)
    {
    
    
        tree[v].llen[que[le]]=tree[v].rlen[que[le]]=tree[v].mlen[que[le]]=1;
        tree[v].sum=que[le];
        return;
    }
    int mid=le+ri>>1;
    build(ls,le,mid),build(rs,mid+1,ri);
    up(v);
}
void fill(int v,int le,int ri)
{
    
    
    if(le<=tree[v].le&&tree[v].ri<=ri)
    {
    
    
        tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=0;
        tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=tree[v].ri-tree[v].le+1;
        tree[v].fill=1,tree[v].clear=tree[v].rev=0;
        return;
    }
    down(v);
    int mid=tree[v].le+tree[v].ri>>1;
    if(le<=mid)fill(ls,le,ri);
    if(mid<ri)fill(rs,le,ri);
    up(v);
}
void clear(int v,int le,int ri)
{
    
    
    if(le<=tree[v].le&&tree[v].ri<=ri)
    {
    
    
        tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=0;
        tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=tree[v].ri-tree[v].le+1;
        tree[v].clear=1,tree[v].fill=tree[v].rev=0;
        return;
    }
    down(v);
    int mid=tree[v].le+tree[v].ri>>1;
    if(le<=mid)clear(ls,le,ri);
    if(mid<ri)clear(rs,le,ri);
    up(v);
}
void rev(int v,int le,int ri)
{
    
    
    if(le<=tree[v].le&&tree[v].ri<=ri)
    {
    
    
        push_rev(v);
        return;
    }
    down(v);
    int mid=tree[v].le+tree[v].ri>>1;
    if(le<=mid)rev(ls,le,ri);
    if(mid<ri)rev(rs,le,ri);
    up(v);
}
int asksum(int v,int le,int ri)
{
    
    
    if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].sum;
    down(v);
    int mid=tree[v].le+tree[v].ri>>1,r=0;
    if(le<=mid)r=asksum(ls,le,ri);
    if(mid<ri)r+=asksum(rs,le,ri);
    return r;
}
int asklen(int v,int le,int ri)
{
    
    
    if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].mlen[1];
    down(v);
    int mid=tree[v].le+tree[v].ri>>1,r=min(tree[rs].le+tree[rs].llen[1]-1,ri)-max(tree[ls].ri-tree[ls].rlen[1]+1,le)+1;
    if(le<=mid)r=max(r,asklen(ls,le,ri));
    if(mid<ri)r=max(r,asklen(rs,le,ri));
    return r;
}
void in()
{
    
    
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",&que[i]);
}
void ac()
{
    
    
    build(1,1,n);
    for(int i=1,op,a,b;i<=m;++i)
    {
    
    
        scanf("%d%d%d",&op,&a,&b);
        ++a,++b;
        if(!op)clear(1,a,b);
        else if(op==1)fill(1,a,b);
        else if(op==2)rev(1,a,b);
        else if(op==3)printf("%d\n",asksum(1,a,b));
        else printf("%d\n",asklen(1,a,b));
    }
}
int main()
{
    
    
    in(),ac();
    //system("pause");
}

第二种写法:

#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=1e5+5;
struct node{
    
    
    int le,ri,llen[2],rlen[2],mlen[2],sum;
    bool clear,fill,rev;
}tree[M<<2];
int n,m,que[M];
void up(int v,int p)
{
    
    
    tree[v].llen[p]=(tree[ls].llen[p]==tree[ls].ri-tree[ls].le+1)?tree[ls].llen[p]+tree[rs].llen[p]:tree[ls].llen[p];
    tree[v].rlen[p]=(tree[rs].rlen[p]==tree[rs].ri-tree[rs].le+1)?tree[rs].rlen[p]+tree[ls].rlen[p]:tree[rs].rlen[p];
    tree[v].mlen[p]=max(tree[ls].rlen[p]+tree[rs].llen[p],max(tree[ls].mlen[p],tree[rs].mlen[p]));
}
void up(int v)
{
    
    
    up(v,0),up(v,1);
    tree[v].sum=tree[ls].sum+tree[rs].sum;
}
void push_fill(int v,int p)
{
    
    
    tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=tree[v].ri-tree[v].le+1;
}
void push_clear(int v,int p)
{
    
    
    tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=0;
}
void push_rev(int v)
{
    
    
    swap(tree[v].llen[0],tree[v].llen[1]);
    swap(tree[v].rlen[0],tree[v].rlen[1]);
    swap(tree[v].mlen[0],tree[v].mlen[1]);
    tree[v].sum=tree[v].ri-tree[v].le+1-tree[v].sum;
    tree[v].rev^=1;
    //if(tree[v].fill||tree[v].clear)swap(tree[v].fill,tree[v].clear);
}
void down(int v)
{
    
    
    if(tree[v].clear)
    {
    
    
        push_clear(ls,1),push_fill(ls,0);
        push_clear(rs,1),push_fill(rs,0);
        tree[ls].clear=1,tree[ls].fill=tree[ls].rev=0;
        tree[rs].clear=1,tree[rs].fill=tree[rs].rev=0;
        tree[ls].sum=tree[rs].sum=0;
        tree[v].clear=0;
    }
    if(tree[v].fill)
    {
    
    
        push_clear(ls,0),push_fill(ls,1);
        push_clear(rs,0),push_fill(rs,1);
        tree[ls].fill=1,tree[ls].clear=tree[ls].rev=0;
        tree[rs].fill=1,tree[rs].clear=tree[rs].rev=0;
        tree[ls].sum=tree[ls].ri-tree[ls].le+1;
        tree[rs].sum=tree[rs].ri-tree[rs].le+1;
        tree[v].fill=0;
    }
    if(tree[v].rev)
    {
    
    
        push_rev(ls),push_rev(rs);
        tree[v].rev=0;
    }
}
void build(int v,int le,int ri)
{
    
    
    tree[v].le=le,tree[v].ri=ri;
    if(le==ri)
    {
    
    
        tree[v].llen[que[le]]=tree[v].rlen[que[le]]=tree[v].mlen[que[le]]=1;
        tree[v].sum=que[le];
        return;
    }
    int mid=le+ri>>1;
    build(ls,le,mid),build(rs,mid+1,ri);
    up(v);
}
void fill(int v,int le,int ri)
{
    
    
    if(le<=tree[v].le&&tree[v].ri<=ri)
    {
    
    
        tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=0;
        tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=tree[v].ri-tree[v].le+1;
        tree[v].fill=1,tree[v].clear=tree[v].rev=0;
        return;
    }
    down(v);
    int mid=tree[v].le+tree[v].ri>>1;
    if(le<=mid)fill(ls,le,ri);
    if(mid<ri)fill(rs,le,ri);
    up(v);
}
void clear(int v,int le,int ri)
{
    
    
    if(le<=tree[v].le&&tree[v].ri<=ri)
    {
    
    
        tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=0;
        tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=tree[v].ri-tree[v].le+1;
        tree[v].clear=1,tree[v].fill=tree[v].rev=0;
        return;
    }
    down(v);
    int mid=tree[v].le+tree[v].ri>>1;
    if(le<=mid)clear(ls,le,ri);
    if(mid<ri)clear(rs,le,ri);
    up(v);
}
void rev(int v,int le,int ri)
{
    
    
    if(le<=tree[v].le&&tree[v].ri<=ri)
    {
    
    
        push_rev(v);
        return;
    }
    down(v);
    int mid=tree[v].le+tree[v].ri>>1;
    if(le<=mid)rev(ls,le,ri);
    if(mid<ri)rev(rs,le,ri);
    up(v);
}
int asksum(int v,int le,int ri)
{
    
    
    if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].sum;
    down(v);
    int mid=tree[v].le+tree[v].ri>>1,r=0;
    if(le<=mid)r=asksum(ls,le,ri);
    if(mid<ri)r+=asksum(rs,le,ri);
    return r;
}
int asklen(int v,int le,int ri)
{
    
    
    if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].mlen[1];
    down(v);
    int mid=tree[v].le+tree[v].ri>>1,r=min(tree[rs].le+tree[rs].llen[1]-1,ri)-max(tree[ls].ri-tree[ls].rlen[1]+1,le)+1;
    if(le<=mid)r=max(r,asklen(ls,le,ri));
    if(mid<ri)r=max(r,asklen(rs,le,ri));
    return r;
}
void in()
{
    
    
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",&que[i]);
}
void ac()
{
    
    
    build(1,1,n);
    for(int i=1,op,a,b;i<=m;++i)
    {
    
    
        scanf("%d%d%d",&op,&a,&b);
        ++a,++b;
        if(!op)clear(1,a,b);
        else if(op==1)fill(1,a,b);
        else if(op==2)rev(1,a,b);
        else if(op==3)printf("%d\n",asksum(1,a,b));
        else printf("%d\n",asklen(1,a,b));
    }
}
int main()
{
    
    
    in(),ac();
    //system("pause");
}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/113357329
今日推荐