【线段树】序列操作

序列操作

operation

【题目描述】

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

【数据范围】

   对于30%的数据,1<=n, m<=1000

   对于100%的数据,1<=n, m<=100000



SC2010省选题目。


很BT的一道题,做了我一个下午加上一个晚上,总共275行,吓哭了。


神奇的是,今天晚上一晚上都没有调,仅仅是静态查错了两个小时就AC了,貌似效率是很高的,希望做出了这道题之后就能入门线段树了。


今天我听取了很多人的意见。一是OJ说的,要一个功能一个功能地添加。二是王哥说的很重要的静态差错。


这道题和Rqnoj626那道小白逛公园基本上是一样的思路,当找连续最长的时候,分三种情况:在左边找连续最长,在右边找连续最长,在中间找连续最长。

但是由于这道题特殊性,维护maxl和maxr的时候,不能够像626那样做。因为不能够直接取左儿子或右儿子的sum,因为0此时没有被取到。

(可以证明,最后维护出来的maxn总是包含了maxl和maxr这两种情况)

——————————————————————————————————————————————————————————————————————————

先分模块来讲:

build()是很标准的,和626一模一样。


0和1对应的模块比较标准,不过对于我这个新手,还是花了很长时间来理解,检查。

首先如果当前区间值等于要填充的值,就直接返回。

如果要填充的区间包含了当前区间,则填充。

接下来,同626,很重要的一个部分,如果当前节点有懒标记(我听WG的,就用同填充线段那种方式,用-1表示杂色或者说懒标记(没有用LX用的那个布尔懒标记)),则将当前节点的信息向下传递。(这个步骤虽然让线段树有点退化,但是不会完全退化,也是效率高的重要原因)

然后就是标准的分情况讨论。(如CY说的那样,线段树都分成4种情况),之后更新(只要是涉及到修改的,建树、翻转、设置,都要有更新)。


向下传递在除了build之外所有的模块中都用到了,而且一模一样。(注意:查询模块也必须有向下传递,很容易理解但是容易忽略)

容易打错的地方是:如果当前节点状态为1,则左子节点的sum值=m-l+1,右节点sum值=r-m。


翻转模块与更改模块几乎一模一样。只有边界稍有不同。flip的边界是找到一块纯色区域且在被待修改区间包含的一个区间,然后将状态取反,就一模一样了。


我写冗杂了,其实count,和longgest功能是完全一样的,但是我分开写了。只不过也许这样反而让程序效率变高了,因为几乎每个点都比其他同学快。

很简单,与626一模一样,注意好懒标记向下传就好。


updata与626一模一样。

——————————————————————————————————————————————————————————————————————————

总结一些回忆得起来的经验


1、做的时候,要注意函数体内的return,有的重要的函数常常放在了最后,而很早就return了,没有执行这些重要的函数。比如说有时候的后序遍历的updata。


2、要训练自己的全局意识,比如说今天打了很多重复的代码,最后才发现是一模一样的,那个updata和那个向下传递就是例子,调试了很久才发现实现是一模一样的才把他们放入一个单独模块里,耽搁时间了。一开始应该仔细考虑这些程序内在的联系才好。

还有longgest和count其实也是一模一样的。


3。。。


#include <cstdio>

struct node
{
    long sta;
    long s1;
    long maxl;
    long maxr;
    long maxn;
};

node tree[400002];

long n;long m;
bool que[100002];

void updata(node& ans,node& u,node& v)
{
    if (u.sta == 1)
        ans.maxl = u.s1 + v.maxl;
    else ans.maxl = u.maxl;

    if (v.sta == 1)
        ans.maxr = v.s1 + u.maxr;
    else ans.maxr = v.maxr;

    if (u.maxn > v.maxn)
        ans.maxn = u .maxn;
    else ans.maxn = v.maxn;
    if (ans.maxn < u.maxr+v.maxl)
        ans.maxn = u.maxr+v.maxl;

    if (u.sta == v.sta)
        ans.sta = u.sta;
    else ans.sta = -1;
    ans.s1 = u.s1+v.s1;
}

void set(long l,long r,long p,long a,long b,long c)
{
    long m = (l+r)>>1;
    if (tree[p].sta == c)
    {
        return;
    }
    if (a <= l && b >= r)
    {
        tree[p].sta = c;
        if (c == 1)
        {
            tree[p].s1 = r-l+1;
            tree[p].maxl = tree[p].maxr = tree[p].maxn = r-l+1;
        }
        else
        {
            tree[p].s1 = 0;
            tree[p].maxl = tree[p].maxr = tree[p].maxn = 0;
        }
        return;
    }
    if (tree[p].sta > -1)
    {
        tree[p<<1].sta = tree[(p<<1)+1].sta = tree[p].sta;
        if (tree[p].sta == 0)
        {
            tree[p<<1].s1 = tree[(p<<1)+1].s1 = 0;
            tree[p<<1].maxl = tree[p<<1].maxr = tree[p<<1].maxn = 0;
            tree[(p<<1)+1].maxl = tree[(p<<1)+1].maxr = tree[(p<<1)+1].maxn = 0;
        }
        else
        {
            tree[p<<1].s1 = m-l+1;
            tree[(p<<1)+1].s1 = r-m;
            tree[p<<1].maxl = tree[p<<1].maxr = tree[p<<1].maxn = m-l+1;
            tree[(p<<1)+1].maxl = tree[(p<<1)+1].maxr = tree[(p<<1)+1].maxn = r-m;
        }
    }
    if (b <= m)
    {
        set(l,m,p<<1,a,b,c);
    }
    else if (a > m)
    {
        set(m+1,r,(p<<1)+1,a,b,c);
    }
    else
    {
        set(l,m,p<<1,a,b,c);
        set(m+1,r,(p<<1)+1,a,b,c);
    }
    updata(tree[p],tree[p<<1],tree[(p<<1)+1]);
}

void build(long l,long r,long p)
{
    long m = (l+r)>>1;
    if (l == r)
    {
        tree[p].sta = que[l];
        if (que[l] == 1)
            tree[p].maxl =  tree[p].maxr = tree[p].maxn = tree[p].s1 = 1;
        else
            tree[p].maxl =  tree[p].maxr = tree[p].maxn = tree[p].s1 = 0;
        return;
    }
    build(l,m,p<<1);
    build(m+1,r,(p<<1)+1);
    updata(tree[p],tree[p<<1],tree[(p<<1)+1]);
}

long count(long l,long r,long p,long a,long b)
{
    long m = (l+r)>>1;
    if (a <= l && b>= r)
    {
        return tree[p].s1;
    }
    if (tree[p].sta > -1)
    {
        tree[p<<1].sta = tree[(p<<1)+1].sta = tree[p].sta;
        if (tree[p].sta == 0)
        {
            tree[p<<1].s1 = tree[(p<<1)+1].s1 = 0;
            tree[p<<1].maxl = tree[p<<1].maxr = tree[p<<1].maxn = 0;
            tree[(p<<1)+1].maxl = tree[(p<<1)+1].maxr = tree[(p<<1)+1].maxn = 0;
        }
        else
        {
            tree[p<<1].s1 = m-l+1;
            tree[(p<<1)+1].s1 = r-m;
            tree[p<<1].maxl = tree[p<<1].maxr = tree[p<<1].maxn = m-l+1;
            tree[(p<<1)+1].maxl = tree[(p<<1)+1].maxr = tree[(p<<1)+1].maxn = r-m;
        }
    }
    if (b <= m)
    {
        return count(l,m,p<<1,a,b);
    }
    if (a > m)
    {
        return count(m+1,r,(p<<1)+1,a,b);
    }
    {
        long u = count(l,m,p<<1,a,b);
        long v = count(m+1,r,(p<<1)+1,a,b);
        return u+v;
    }
}

void flip(long l,long r,long p,long a,long b)
{
    long m = (l+r)>>1;
    if (a<=l&&b>=r&&tree[p].sta > -1)
    {
        tree[p].sta = (tree[p].sta+1)&1;
        if (tree[p].sta == 0)
        {
            tree[p].s1 = 0;
            tree[p].maxl = tree[p].maxr = tree[p].maxn = 0;
        }
        else
        {
            tree[p].s1 = r-l+1;
            tree[p].maxl = tree[p].maxr = tree[p].maxn = r-l+1;
        }
        return;
    }
    if (tree[p].sta > -1)
    {
        tree[p<<1].sta = tree[(p<<1)+1].sta = tree[p].sta;
        if (tree[p].sta == 0)
        {
            tree[p<<1].s1 = tree[(p<<1)+1].s1 = 0;
            tree[p<<1].maxl = tree[p<<1].maxn = tree[p<<1].maxr = 0;
            tree[(p<<1)+1].maxl = tree[(p<<1)+1].maxn = tree[(p<<1)+1].maxr = 0;
        }
        else
        {
            tree[p<<1].s1 = m-l+1;
            tree[(p<<1)+1].s1 = r-m;
            tree[p<<1].maxl = tree[p<<1].maxn = tree[p<<1].maxr = m-l+1;
            tree[(p<<1)+1].maxl = tree[(p<<1)+1].maxn = tree[(p<<1)+1].maxr = r-m;
        }
    }
    if (b <= m)
    {
        flip(l,m,p<<1,a,b);
    }
    else if (a > m)
    {
        flip(m+1,r,(p<<1)+1,a,b);
    }
    else
    {
        flip(l,m,p<<1,a,b);
        flip(m+1,r,(p<<1)+1,a,b);
    }
    updata(tree[p],tree[p<<1],tree[(p<<1)+1]);
}

node longgest(long l,long r,long p,long a,long b)
{
    long m = (l+r)>>1;
    if (a <= l && b >= r)
        return tree[p];

    if (tree[p].sta > -1)
    {
        tree[p<<1].sta = tree[(p<<1)+1].sta = tree[p].sta;
        if (tree[p].sta == 0)
        {
            tree[p<<1].s1 = tree[(p<<1)+1].s1 = 0;
            tree[p<<1].maxl = tree[p<<1].maxn = tree[p<<1].maxr = 0;
            tree[(p<<1)+1].maxl = tree[(p<<1)+1].maxn = tree[(p<<1)+1].maxr = 0;
        }
        else
        {
            tree[p<<1].s1 = m-l+1;
            tree[(p<<1)+1].s1 = r-m;
            tree[p<<1].maxl = tree[p<<1].maxn = tree[p<<1].maxr = m-l+1;
            tree[(p<<1)+1].maxl = tree[(p<<1)+1].maxn = tree[(p<<1)+1].maxr = r-m;
        }
    }
    if (a > m)
    {
        return longgest(m+1,r,(p<<1)+1,a,b);
    }
    if (b <= m)
    {
        return longgest(l,m,p<<1,a,b);
    }
    node u = longgest(l,m,p<<1,a,b);
    node v = longgest(m+1,r,(p<<1)+1,a,b);

    node ans;
    updata(ans,u,v);

    return ans;
}

int main()
{
    freopen("operation.in","r",stdin);
    freopen("operation.out","w",stdout);
    scanf("%ld%ld",&n,&m);
    for (long i=1;i<n+1;i++)
        scanf("%ld",que+i);
    build(1,n,1);
    for (long i=1;i<m+1;i++)
    {
        long op;long a;long b;

        scanf("%ld%ld%ld",&op,&a,&b);
        a++;b++;

        switch(op)
        {
            case 0:
                set(1,n,1,a,b,0);
                break;
            case 1:
                set(1,n,1,a,b,1);
                break;
            case 2:
                flip(1,n,1,a,b);
                break;
            case 3:
                printf("%ld\n",count(1,n,1,a,b));
                break;
            case 4:
                printf("%ld\n",longgest(1,n,1,a,b).maxn);
                break;
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值