【题解】HDU3397 Sequence operation

传送门
原题是SCOI2010序列操作。HDU上的版本是其加强版(多组数据),还要初始化。我是不会对你说我不加初始化然后在HDU上WA了无数次的

没错,这就是一道线段树区间合并和区间修改的综合模板神题。

线段树区间合并不会的童鞋们请参考


接下来讲讲如何实现这几种操作:

  • 0 a b change all characters into ‘0’s in [a , b]
    意为把区间 [ a , b ] 中的所有数改成0,就是板子里的 s e t ( ) ,略过。
  • 1 a b change all characters into ‘1’s in [a , b]
    意为把区间 [ a , b ] 中的所有数改成1,还是板子里的 s e t ( ) ,略过。
  • 2 a b change all ‘0’s into ‘1’s and change all ‘1’s into ‘0’s in [a, b]
    意为把区间 [ a , b ] 中的0和1对调,由于存在2操作和3操作,使得我们像板子里一样只维护关于1的信息变得不可行,所以我们还要维护关于0的信息,所以这题就特别恶心。 p u s h u p ( ) 中还要加入对0的维护。 r e v e r s e ( ) 的具体写法和一般线段树几乎完全相同。
  • 3 a b output the number of ‘1’s in [a, b]
    意为统计区间 [ a , b ] 中1的个数,很显然,等效于求区间 [ a , b ] 中数的总和,对策也很好想,像一般线段树一样维护一个 c o u n t 统计区间 [ a , b ] 的总和, q u e r y s u m 统计。
  • 4 a b output the length of the longest continuous ‘1’ string in [a , b]
    意为统计区间 [ a , b ] 中最长的连续的1的长度,相当于板子里的 q u e r y ( ) ,略过。

经过对几个操作的分析,我们可以发现这道题其实就是几个操作混合了一下,本身并算不上难,细节比较多,错的话调试非常麻烦而已。
说到细节,我就来说明一下几个重要的细节:

  • p u s h u p ( ) 中不仅要有对1的维护,也要包含对0的维护和对区间和的维护。
  • r e v e r s e ( ) 中要将所有的信息重置,1的信息和0的信息要对应地对调。假如如见单一, c o l o r 也要取反,区间和要修改。
  • p u s h d o w n ( ) 中一定要先翻转然后覆盖。
  • c r e a t ( ) 进行值覆盖的时候要将 r e v e r s e d 标记清除。
  • 最后一点,也是很坑的一点,不要忘了初始化。。。

C o d e

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define max(x, y) ((x) > (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y))
using std::swap;
int a[100005];
struct SegTree {
    #define lc(o) o << 1
    #define rc(o) o << 1 | 1
    #define mid ((l + r) >> 1)
    #define MS(array) memset(array, 0, sizeof array)
    struct Ans { 
        int ls, rs, s; 
        Ans(int ls, int rs, int s) : ls(ls), rs(rs), s(s) {}
    };
    static const int MAXSIZE = 100000 + 5;
    int lsum1[MAXSIZE << 2], rsum1[MAXSIZE << 2], sum1[MAXSIZE << 2], color[MAXSIZE << 2];
    int lsum0[MAXSIZE << 2], rsum0[MAXSIZE << 2], sum0[MAXSIZE << 2], sum[MAXSIZE << 2];
    bool reversed[MAXSIZE << 2];
    void clear() { //初始化
        MS(lsum1); MS(rsum1); MS(sum1); MS(color);
        MS(lsum0); MS(rsum0); MS(sum0); MS(sum);
        MS(reversed);
    }
    void creat(int o, int l, int r, int value) { //值覆盖
        color[o] = value; reversed[o] = false;
        lsum1[o] = rsum1[o] = sum1[o] = sum[o] = value ? r - l + 1 : 0;
        lsum0[o] = rsum0[o] = sum0[o] = value ? 0 : r - l + 1;
    }
    void cover(int o, int l, int r) { //翻转覆盖
        reversed[o] ^= true;
        swap(lsum1[o], lsum0[o]);
        swap(rsum1[o], rsum0[o]);
        swap(sum1[o], sum0[o]);
        if (color[o] != -1) color[o] ^= 1;
        sum[o] = (r - l + 1) - sum[o];
    }
    void pushdown(int o, int l, int r) { //pushdown()
        if (reversed[o]) {  //先判断翻转覆盖
            cover(lc(o), l, mid);
            cover(rc(o), mid + 1, r);
            reversed[o] = false;
        }
        if (color[o] != -1) {
            creat(lc(o), l, mid, color[o]);
            creat(rc(o), mid + 1, r, color[o]);
        }
    }
    void pushup(int o) { //繁琐的pushup()
        lsum1[o] = color[lc(o)] == 1 ? lsum1[lc(o)] + lsum1[rc(o)] : lsum1[lc(o)];
        rsum1[o] = color[rc(o)] == 1 ? rsum1[lc(o)] + rsum1[rc(o)] : rsum1[rc(o)];
        sum1[o] = max(rsum1[lc(o)] + lsum1[rc(o)], max(sum1[lc(o)], sum1[rc(o)]));
        lsum0[o] = color[lc(o)] == 0 ? lsum0[lc(o)] + lsum0[rc(o)] : lsum0[lc(o)];
        rsum0[o] = color[rc(o)] == 0 ? rsum0[lc(o)] + rsum0[rc(o)] : rsum0[rc(o)];
        sum0[o] = max(rsum0[lc(o)] + lsum0[rc(o)], max(sum0[lc(o)], sum0[rc(o)]));
        if (sum1[o] == 0) color[o] = 0; else if (sum0[o] == 0) color[o] = 1; else color[o] = -1;
        if (color[o] != -1) reversed[o] = false;
        sum[o] = sum[lc(o)] + sum[rc(o)];
    }
    void set(int o, int l, int r, int L, int R, int value) {
        if (l > R || r < L) return;
        else if (L <= l && r <= R) creat(o, l, r, value);
        else {
            pushdown(o, l, r);
            set(lc(o), l, mid, L, R, value);
            set(rc(o), mid + 1, r, L, R, value);
            pushup(o);
        }
    }
    void reverse(int o, int l, int r, int L, int R) {
        if (l > R || r < L) return;
        else if (L <= l && r <= R) cover(o, l, r);
        else {
            pushdown(o, l, r);
            reverse(lc(o), l, mid, L, R);
            reverse(rc(o), mid + 1, r, L, R);
            pushup(o);
        }
    }
    int query_sum(int o, int l, int r, int L, int R) {
        if (l > R || r < L) return 0;
        else if (L <= l && r <= R) return sum[o];
        else {
            pushdown(o, l, r);
            return query_sum(lc(o), l, mid, L, R) + query_sum(rc(o), mid + 1, r, L, R);
        }
    }
    Ans query_len(int o, int l, int r, int L, int R) {
        if (l > R || r < L) return Ans(0, 0, 0);
        else if (L <= l && r <= R) return Ans(lsum1[o], rsum1[o], sum1[o]);
        else {
            pushdown(o, l, r);
            if (R <= mid) return query_len(lc(o), l, mid, L, R);
            if (L > mid) return query_len(rc(o), mid + 1, r, L, R);
            Ans p = query_len(lc(o), l, mid, L, R);
            Ans q = query_len(rc(o), mid + 1, r, L, R);
            return Ans(p.ls == mid - l + 1 ? p.ls + q.ls : p.ls, 
                       q.rs == r - mid ? p.rs + q.rs : q.rs, 
                       max(max(p.s, q.s), p.rs + q.ls));
        }
    }
    void build(int o, int l, int r) {
        if (l > r) return;
        else if (l == r) creat(o, l, r, a[l]);
        else {
            build(lc(o), l, mid);
            build(rc(o), mid + 1, r);
            pushup(o);
        }
    }
};
SegTree root;
int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) 
            scanf("%d", &a[i]);
        root.clear();
        root.build(1, 1, n);
        for (int i = 1; i <= m; i++) {
            int opt, x, y;
            scanf("%d%d%d", &opt, &x, &y);
            x++; y++;
            if (opt == 0) root.set(1, 1, n, x, y, 0);
            else if (opt == 1) root.set(1, 1, n, x, y, 1);
            else if (opt == 2) root.reverse(1, 1, n, x, y);
            else if (opt == 3) printf("%d\n", root.query_sum(1, 1, n, x, y));
            else if (opt == 4) printf("%d\n", root.query_len(1, 1, n, x, y).s);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/diogenes_/article/details/80528905