zoukankan      html  css  js  c++  java
  • [BZOJ1858] [SCOI2010] 序列操作 解题报告 (线段树)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1858

    Description

    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都需要给出回答,聪明的程序员们,你们能帮助他吗?

    Input

    输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目 第二行包括n个数,表示序列的初始状态 接下来m行,每行3个数,op, a, b,(0 < = op < = 4,0 < = a < = b)

    Output

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

    Sample Input

    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

    Sample Output

    5
    2
    6
    5

    HINT

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

     

    题解:

      考虑怎么对标记进行维护,使用full标记判断该节点所代表的区间是否是同一数字;c标记代表0/1操作,将该节点全部赋值,同时更新full标记

      在翻转标记rev的下推过程中注意偶数次翻转等于没有操作,而赋值操作会清空rev标记。在程序中我们考虑另写一个color函数来将节点染色(全部赋值一个数)

      关键之处在于合并,对于连续的1的个数其实很好维护,细节在于l0,l1,r0,r1即从区间左边到右边和右边到左边有多少个连续的1;值得注意的是合并操作返回的是一颗子树

      那么在统计最大连续的1的时候,我们不能采取累加的方式,而是要在指定区间里合并出一颗新的树,直接输出它的mx1,即最大的连续1的个数

      笔者强调,本题细节较多,请读者耐心阅读并尝试自己打完代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define N 100005
    using namespace std;
    int n,m; 
    int a[N];
    struct seg
    {
        int l,r;
        int l0,l1,r0,r1,mx0,mx1,sum0,sum1;
        int rev,c,full;
        }t[N<<2];
    void rev(int k)
    {
        swap(t[k].l0,t[k].l1);
        swap(t[k].r0,t[k].r1);
        swap(t[k].mx0,t[k].mx1);
        swap(t[k].sum0,t[k].sum1);
        if(t[k].full!=-1)t[k].full^=1;
    }
    void color(int k,int v)
    {
        t[k].rev=0;
        int s=t[k].r-t[k].l+1;
        if(v==0)
        {
           t[k].sum0=t[k].l0=t[k].r0=t[k].mx0=s;
           t[k].sum1=t[k].l1=t[k].r1=t[k].mx1=0;
        }
        else
        {
           t[k].sum0=t[k].l0=t[k].r0=t[k].mx0=0;
           t[k].sum1=t[k].l1=t[k].r1=t[k].mx1=s;
        }
        t[k].full=v;
    }
    seg merge(seg a,seg b) 
    {
        seg tmp;tmp.l=a.l;tmp.r=b.r;
        tmp.rev=0;tmp.c=-1;
        tmp.l0=a.l0;tmp.l1=a.l1;
        tmp.r0=b.r0;tmp.r1=b.r1;
        tmp.mx0=max(a.mx0,b.mx0);
        tmp.mx1=max(a.mx1,b.mx1);
        tmp.mx0=max(tmp.mx0,a.r0+b.l0);
        tmp.mx1=max(tmp.mx1,a.r1+b.l1);
        tmp.sum0=a.sum0+b.sum0;
        tmp.sum1=a.sum1+b.sum1;
        if(a.full==0)tmp.l0=a.mx0+b.l0;
        else if(a.full==1)tmp.l1=a.mx1+b.l1;
        if(b.full==0)tmp.r0=b.mx0+a.r0;
        else if(b.full==1)tmp.r1=b.mx1+a.r1;
        if(a.full==b.full)
           tmp.full=a.full;
        else tmp.full=-1;
        return tmp;
    }
    void pushup(int k)
    {
        t[k]=merge(t[k<<1],t[k<<1|1]);
    }
    void pushdown(int k)
    {
        if(t[k].l==t[k].r)return;
        if(t[k].c!=-1)
        {
            t[k<<1].c=t[k<<1|1].c=t[k].c;
            color(k<<1,t[k].c);color(k<<1|1,t[k].c);
            t[k].c=-1;
        }
        if(t[k].rev)
        {
            t[k<<1].rev^=1;
            t[k<<1|1].rev^=1;
            rev(k<<1);rev(k<<1|1);
            t[k].rev=0;
        }
    }
    void build(int k,int l,int r)
    {
        t[k].l=l;t[k].r=r;
        t[k].c=-1;
        if(l==r)
        {
            t[k].full=a[l];
            if(t[k].full)
            {t[k].l1=t[k].r1=t[k].mx1=t[k].sum1=1;}
            else
            {t[k].l0=t[k].r0=t[k].mx0=t[k].sum0=1;}
            return;
        }
        int mid=(l+r)>>1;
        build(k<<1,l,mid);build(k<<1|1,mid+1,r);
        pushup(k);
    }
    void change(int k,int x,int y,int v)
    {
        pushdown(k);
        int l=t[k].l,r=t[k].r;
        if(l==x&&r==y)
        {
            color(k,v);
            t[k].c=v;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=y)change(k<<1,x,y,v);
        else if(mid<x)change(k<<1|1,x,y,v);
        else
        {
            change(k<<1,x,mid,v);
            change(k<<1|1,mid+1,y,v);
        }
        pushup(k);
    }
    void rever(int k,int x,int y)
    {
        pushdown(k);
        int l=t[k].l,r=t[k].r;
        if(l==x&&r==y)
        {
            rev(k);
            t[k].rev=1;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=y)rever(k<<1,x,y);
        else if(mid<x)rever(k<<1|1,x,y);
        else
        {
            rever(k<<1,x,mid);
            rever(k<<1|1,mid+1,y);
        }
        pushup(k);
    }
    seg ask(int k,int x,int y)
    {
        pushdown(k);
        int l=t[k].l,r=t[k].r;
        if(l==x&&y==r)return t[k];
        int mid=(l+r)>>1;
        if(mid>=y)return ask(k<<1,x,y);
        else if(mid<x)return ask(k<<1|1,x,y);
        else return merge(ask(k<<1,x,mid),ask(k<<1|1,mid+1,y));
    }
    int asksum(int k,int x,int y)
    {
        pushdown(k);
        int l=t[k].l,r=t[k].r;
        if(l==x&&y==r)return t[k].sum1;
        int mid=(l+r)>>1;
        if(mid>=y)return asksum(k<<1,x,y);
        else if(mid<x)return asksum(k<<1|1,x,y);
        else return asksum(k<<1,x,mid)+asksum(k<<1|1,mid+1,y);
    }
    int main()
    {
        //freopen("a.in","r",stdin);
        //freopen("b.out","w",stdout);
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) 
        scanf("%d",&a[i]);
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            int f,x,y;
            scanf("%d%d%d",&f,&x,&y);
            x++;y++;
            switch(f)
            {
                case 0:change(1,x,y,0);break;
                case 1:change(1,x,y,1);break;
                case 2:rever(1,x,y);break;
                case 3:printf("%d
    ",asksum(1,x,y));break;
                case 4:printf("%d
    ",ask(1,x,y).mx1);break;
            }
        }
        return 0;
    }
  • 相关阅读:
    [luogu4799 CEOI2015 Day2] 世界冰球锦标赛(折半搜索)
    [luogu3230 HNOI2013] 比赛 (搜索+Hash)
    [luogu2317 HNOI2005] 星际贸易 (dp)
    [luogu2414 NOI2011]阿狸的打字机 (AC自动机)
    [bzoj3507 Cqoi2014]通配符匹配 (hash+DP)
    [luogu2054 AHOI2005] 洗牌 (数论)
    bzoj1491 [NOI2007]社交网络
    bzoj1022 [SHOI2008]小约翰的游戏John
    bzoj1088 [SCOI2005]扫雷Mine
    bzoj1295 [SCOI2009]最长距离
  • 原文地址:https://www.cnblogs.com/xxzh/p/9351147.html
Copyright © 2011-2022 走看看