• P2572 [SCOI2010] 序列操作【线段树】


    题意

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

    思路

    这是一道比较经典的线段树板子题,所有的操作都比较经典,维护也比较简单,只是比较繁琐,需要细心耐心地写代码。
    考虑怎么维护题目中要求的信息,首先需要维护区间0和1的个数 s 0 s_0 s0 s 1 s_1 s1,为了维护最大连续0和最大连续1,经典的做法是维护包括区间左端点的最大连续0/1长度, l m x 0 / l m x 1 lmx_0/lmx_1 lmx0/lmx1(简称左连续),还有包括区间右端点的最大连续0/1长度, r m x 0 / r m x 1 rmx_0/rmx_1 rmx0/rmx1(简称右连续),还有考虑完整个区间的最大连续0/1长度, m x 0 / m x 1 mx_0/mx_1 mx0/mx1,区间合并的操作也比较经典了,这里就不再多说。
    区间设置和区间反转需要两个懒标记 s e t l z setlz setlz r e v l z revlz revlz分别表示,标记下传的时候记得先下传 s e t l z setlz setlz再下传 r e v l z revlz revlz
    代码还是不够简洁,合并区间的时候写成结构体形式比较好(懒得改了)。

    代码

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    typedef long long LL;
    typedef pair<int, int> PII;
    
    const int N = 100005;
    
    int a[N];
    
    struct Tree
    {
        int l, r;
        int s1, s0;
        int mx1, mx0;
        int lmx1, rmx1;
        int lmx0, rmx0;
        int setlz, revlz;
    }t[N << 2];
    
    void push_up(int i)
    {
        t[i].s1 = t[i << 1].s1 + t[i << 1 | 1].s1;
        t[i].s0 = t[i << 1].s0 + t[i << 1 | 1].s0;
    
        t[i].mx1 = max(t[i << 1].mx1, t[i << 1 | 1].mx1);
        t[i].mx1 = max(t[i << 1].rmx1 + t[i << 1 | 1].lmx1, t[i].mx1);
        t[i].lmx1 = t[i << 1].lmx1;
        if (t[i].lmx1 == t[i << 1].r - t[i << 1].l + 1) t[i].lmx1 += t[i << 1 | 1].lmx1;
        t[i].rmx1 = t[i << 1 | 1].rmx1;
        if (t[i].rmx1 == t[i << 1 | 1].r - t[i << 1 | 1].l + 1) t[i].rmx1 += t[i << 1].rmx1;
    
        t[i].mx0 = max(t[i << 1].mx0, t[i << 1 | 1].mx0);
        t[i].mx0 = max(t[i << 1].rmx0 + t[i << 1 | 1].lmx0, t[i].mx0);
        t[i].lmx0 = t[i << 1].lmx0;
        if (t[i].lmx0 == t[i << 1].r - t[i << 1].l + 1) t[i].lmx0 += t[i << 1 | 1].lmx0;
        t[i].rmx0 = t[i << 1 | 1].rmx0;
        if (t[i].rmx0 == t[i << 1 | 1].r - t[i << 1 | 1].l + 1) t[i].rmx0 += t[i << 1].rmx0;
    }
    
    void Set(int i, int tag)
    {
        if (tag)
        {
            t[i].s0 = t[i].mx0 = t[i].rmx0 = t[i].lmx0 = 0;
            t[i].s1 = t[i].mx1 = t[i].rmx1 = t[i].lmx1 = t[i].r - t[i].l + 1;
        }
        else 
        {
            t[i].s0 = t[i].mx0 = t[i].rmx0 = t[i].lmx0 = t[i].r - t[i].l + 1;
            t[i].s1 = t[i].mx1 = t[i].rmx1 = t[i].lmx1 = 0;
        }
        t[i].setlz = tag;
        t[i].revlz = 0;
    }
    
    void Rev(int i)
    {
        swap(t[i].s0, t[i].s1);
        swap(t[i].lmx0, t[i].lmx1);
        swap(t[i].rmx0, t[i].rmx1);
        swap(t[i].mx0, t[i].mx1);
        t[i].revlz ^= 1;
    }
    
    void push_down(int i)
    {
        if (t[i].setlz != -1) 
            Set(i << 1, t[i].setlz), Set(i << 1 | 1, t[i].setlz), t[i].setlz = -1;
        if (t[i].revlz)
            Rev(i << 1), Rev(i << 1 | 1), t[i].revlz = 0;
    }
    
    void build(int i, int l, int r)
    {
        t[i].l = l, t[i].r = r;
        t[i].setlz = -1;
        if (l == r)
        {
            if (a[l])
                t[i].s1 = t[i].mx1 = t[i].lmx1 = t[i].rmx1 = 1;
            else
                t[i].s0 = t[i].mx0 = t[i].lmx0 = t[i].rmx0 = 1;
            return;
        }
        int mid = (l + r) >> 1;
        build(i << 1, l, mid);
        build(i << 1 | 1, mid + 1, r);
        push_up(i);
    }
    
    void updateSet(int i, int l, int r, int k)
    {
        if (l <= t[i].l && t[i].r <= r) 
        {
            Set(i, k);
            return;
        }
        push_down(i);
        int mid = (t[i].l + t[i].r) >> 1;
        if (l <= mid) updateSet(i << 1, l, r, k);
        if (r > mid) updateSet(i << 1 | 1, l, r, k);
        push_up(i);
    }
    
    void updateRev(int i, int l, int r)
    {
        if (l <= t[i].l && t[i].r <= r)
        {
            Rev(i);
            return;
        }
        push_down(i);
        int mid = (t[i].l + t[i].r) >> 1;
        if (l <= mid) updateRev(i << 1, l, r);
        if (r > mid) updateRev(i << 1 | 1, l, r);
        push_up(i);
    }
    
    int querySum(int i, int l, int r)
    {
        if (l <= t[i].l && t[i].r <= r) return t[i].s1;
        push_down(i);
        int mid = (t[i].l + t[i].r) >> 1;
        int s = 0;
        if (l <= mid) s += querySum(i << 1, l, r);
        if (r > mid) s += querySum(i << 1 | 1, l, r);
        return s;
    }
    
    Tree queryMx(int i, int l, int r)
    {
        if (l <= t[i].l && t[i].r <= r) return t[i];
        push_down(i);
        int mid = (t[i].l + t[i].r) >> 1;
        if (l > mid) return queryMx(i << 1 | 1, l, r);
        else if( r <= mid) return queryMx(i << 1, l, r);
        else 
        {
            Tree ans;
            Tree ls = queryMx(i << 1, l, r), rs = queryMx(i << 1 | 1, l, r);
            ans.s1 = ls.s1 + rs.s1;
            ans.s0 = ls.s0 + rs.s0;
            ans.mx1 = max(ls.mx1, rs.mx1);
            ans.mx1 = max(ls.rmx1 + rs.lmx1, ans.mx1);
            ans.lmx1 = ls.lmx1;
            if (ans.lmx1 == ls.r - ls.l + 1) ans.lmx1 += rs.lmx1;
            ans.rmx1 = rs.rmx1;
            if (ans.rmx1 == rs.r - rs.l + 1) ans.rmx1 += ls.rmx1;
    
            ans.mx0 = max(ls.mx0, rs.mx0);
            ans.mx0 = max(ls.rmx0 + rs.lmx0, ans.mx0);
            ans.lmx0 = ls.lmx0;
            if (ans.lmx0 == ls.r - ls.l + 1) ans.lmx0 += rs.lmx0;
            ans.rmx0 = rs.rmx0;
            if (ans.rmx0 == rs.r - rs.l + 1) ans.rmx0 += ls.rmx0;
            return ans;
        }
    }
    
    int main()
    {
        #ifdef ZYCMH
        freopen("1.in", "r", stdin);
        freopen("1.out", "w", stdout);
        #endif
        
        int n, m;
        scanf("%d%d", &n, &m);
    
        for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
    
        build(1, 1, n);
    
        // printf("sum = %d\n", querySum(1, 1, 6));
    
        for (int i = 1; i <= m; i ++ )
        {
            int op;
            int l, r;
            scanf("%d%d%d", &op, &l, &r);
            l ++, r ++;
            if (op == 0) updateSet(1, l, r, 0);
            else if(op == 1) updateSet(1, l, r, 1);
            else if(op == 2) updateRev(1, l, r);
            else if(op == 3) printf("%d\n", querySum(1, l, r));
            else printf("%d\n", queryMx(1, l, r).mx1);
        }
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
  • 相关阅读:
    Pygame中Trivia游戏解析6-3
    HotSpot垃圾算法实现之记忆集与卡表和写屏障
    【uniapp+uView框架】验证码倒计时代码
    JSON和几个的全局异常处理
    mysql8.0卸载
    Netbeans介绍
    ThemeForest – Canvas 7.2.0 – 多用途 HTML5 模板
    Effective C++ 改善程序与设计的55个具体做法笔记与心得 3
    【linux下centos7.9安装docker,docker-composed(root用户)】
    面向对象分析与设计的关系和区别,面向对象的设计概念,面向对象设计准则
  • 原文地址:https://blog.csdn.net/cpp_juruo/article/details/126678809