HDU 3397 Sequence operation(区间合并 + 区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397

题意:给定n个数,由0,1构成。共有5种操作。每个操作输入3个数,op,a,b。

  1. op == 0,将区间[a,b]赋值为0;
  2. op == 1,将区间[a,b]赋值为1;
  3. op == 2,将区间[a,b]内的01反转;
  4. op == 3,查询区间[a,b]中1的个数;
  5. op == 4,查询区间[a,b]中连续1的最大长度;

思路:区间合并 + 区间更新。每个结点存7个数:

  1. 区间内1的个数c1。
  2. 从区间左端点开始连续1的最大长度l1。
  3. 以区间右端点结束连续1的最大长度r1。
  4. 区间内连续1的最大长度m1。
  5. 从区间左端点开始连续0的最大长度l0。
  6. 以区间右端点结束连续0的最大长度r0。
  7. 区间内连续0的最大长度m0。

记录0的连续是为了反转后统计结果方便。

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>

using namespace std;

#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

const int N = 1e5 + 10;
const int INF = 0x7f7f7f7f;

struct Node {
    int c1;
    int l1, r1, m1;
    int l0, r0, m0;

    Node() {}

    Node(int a, int b, int c, int d, int e, int f, int g) {
        c1 = a;
        l1 = b;
        r1 = c;
        m1 = d;
        l0 = e;
        r0 = f;
        m0 = g;
    }

    void reversal(int s) {
        c1 = s;
        swap(l1, l0);
        swap(r1, r0);
        swap(m1, m0);
    }
};

Node node[N << 2];
int cover[N << 2];
int XOR[N << 2];

void pushup(int rt, int l, int r) {
    int m = (l + r) >> 1;
    int lenl = m - l + 1;
    int lenr = r - m;
    node[rt].c1 = node[rt << 1].c1 + node[rt << 1 | 1].c1;

    if (node[rt << 1].l1 == lenl)
        node[rt].l1 = node[rt << 1].l1 + node[rt << 1 | 1].l1;
    else
        node[rt].l1 = node[rt << 1].l1;

    if (node[rt << 1 | 1].r1 == lenr)
        node[rt].r1 = node[rt << 1 | 1].r1 + node[rt << 1].r1;
    else
        node[rt].r1 = node[rt << 1 | 1].r1;

    if (node[rt << 1].l0 == lenl)
        node[rt].l0 = node[rt << 1].l0 + node[rt << 1 | 1].l0;
    else
        node[rt].l0 = node[rt << 1].l0;

    if (node[rt << 1 | 1].r0 == lenr)
        node[rt].r0 = node[rt << 1 | 1].r0 + node[rt << 1].r0;
    else
        node[rt].r0 = node[rt << 1 | 1].r0;

    node[rt].m1 = max(node[rt << 1].r1 + node[rt << 1 | 1].l1,
                    max(node[rt << 1].m1, node[rt << 1 | 1].m1));
    node[rt].m0 = max(node[rt << 1].r0 + node[rt << 1 | 1].l0,
                    max(node[rt << 1].m0, node[rt << 1 | 1].m0));
}

void pushdown(int rt, int l, int r) {
    int m = (l + r) >> 1;
    int lenl = m - l + 1;
    int lenr = r - m;
    if (cover[rt] != -1) {
        if (cover[rt] == 1) {
            node[rt << 1] = Node(lenl, lenl, lenl, lenl, 0, 0, 0);
            node[rt << 1 | 1] = Node(lenr, lenr, lenr, lenr, 0, 0, 0);
        }
        else {
            node[rt << 1] = Node(0, 0, 0, 0, lenl, lenl, lenl);
            node[rt << 1 | 1] = Node(0, 0, 0, 0, lenr, lenr, lenr);
        }
        cover[rt << 1] = cover[rt << 1 | 1] = cover[rt];
        XOR[rt << 1] = XOR[rt << 1 | 1] = 0;
        cover[rt] = -1;
    }
    if (XOR[rt] != 0) {
        node[rt << 1].reversal(lenl - node[rt << 1].c1);
        node[rt << 1 | 1].reversal(lenr - node[rt << 1 | 1].c1);
        if (cover[rt << 1] != -1)
            cover[rt << 1] =  1 - cover[rt << 1];
        else
            XOR[rt << 1] = 1 - XOR[rt << 1];
        if (cover[rt << 1 | 1] != -1)
            cover[rt << 1 | 1] =  1 - cover[rt << 1 | 1];
        else
            XOR[rt << 1 | 1] = 1 - XOR[rt << 1 | 1];
        XOR[rt] = 0;
    }
}

void build(int l, int r, int rt) {
    cover[rt] = -1;
    XOR[rt] = 0;
    if (l == r) {
        int x;
        scanf("%d", &x);
        node[rt] = Node(x, x, x, x, 1 - x, 1 - x, 1 - x);
        return ;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    pushup(rt, l, r);
}

void update(int op, int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) {
        if (op == 2) {
            node[rt].reversal(r - l + 1 - node[rt].c1);
            if (cover[rt] != -1)
                cover[rt] = 1 - cover[rt];
            else
                XOR[rt] = 1 - XOR[rt];
        }
        else {
            node[rt] = (op == 0 ? Node(0, 0, 0, 0, r - l + 1, r - l + 1, r - l + 1) :
                        Node(r - l + 1, r - l + 1, r - l + 1, r - l + 1, 0, 0, 0));
            cover[rt] = op;
            XOR[rt] = 0;
        }
        return ;
    }
    pushdown(rt, l, r);
    int m = (l + r) >> 1;
    if (L <= m)
        update(op, L, R, lson);
    if (R > m)
        update(op, L, R, rson);
    pushup(rt, l, r);
}

Node query(int op, int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) {
        return node[rt];
    }
    pushdown(rt, l, r);
    int m = (l + r) >> 1;
    Node ql = Node(0, 0, 0, 0, 0, 0, 0);
    Node qr = Node(0, 0, 0, 0, 0, 0, 0);
    if (L <= m)
        ql = query(op, L, R, lson);
    if (R > m)
        qr = query(op, L, R, rson);
    pushup(rt, l, r);
    if (op == 3) {
        return Node(ql.c1 + qr.c1, 0, 0, 0, 0, 0, 0);
    }
    else {
        Node res = Node(0, 0, 0, 0, 0, 0, 0);
        res.m1 = max(ql.r1 + qr.l1, max(ql.m1, qr.m1));
        if (ql.l1 == m - l + 1)
            res.l1 = ql.l1 + qr.l1;
        else
            res.l1 = ql.l1;
        if (qr.r1 == r - m)
            res.r1 = qr.r1 + ql.r1;
        else
            res.r1 = qr.r1;
        return res;
    }
}

int main() {
    int t_case;
    scanf("%d", &t_case);
    for (int i_case = 1; i_case <= t_case; i_case++) {
        int n, m;
        scanf("%d%d", &n, &m);
        build(1, n, 1);
        for (int i = 0; i < m; i++) {
            int op, a, b;
            scanf("%d%d%d", &op, &a, &b);
            a++;
            b++;
            if (op <= 2) {
                update(op, a, b, 1, n, 1);
            }
            else {
                Node res = query(op, a, b, 1, n, 1);
                if (op == 3)
                    printf("%d\n", res.c1);
                else
                    printf("%d\n", res.m1);
            }
        }
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-25 05:55:47

HDU 3397 Sequence operation(区间合并 + 区间更新)的相关文章

hdu 3397 Sequence operation 线段树 区间更新 区间合并

题意: 5种操作,所有数字都为0或1 0 a b:将[a,b]置0 1 a b:将[a,b]置1 2 a b:[a,b]中的0和1互换 3 a b:查询[a,b]中的1的数量 4 a b:查询[a,b]中的最长连续1串的长度 这题看题目就很裸,综合了区间更新,区间合并 我一开始把更新操作全放一个变量,但是在push_down的时候很麻烦,情况很多,容易漏,后来改成下面的 更新的操作可以分为两类,一个是置值(stv),一个是互换(swp).如果stv!=-1,则更新儿子节点的stv,并将儿子的sw

hdu 3397 Sequence operation (线段树 区间合并 多重标记)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意: 给你一串01串,有5种操作 0. 区间全部变为0 1.区间全部变为1 2.区间异或 3.询问区间1的个数 4.询问区间被最长连续1的长度 思路: 这5个操作都是比较基础的线段树操作,难点在于有两种修改操作,这类题之前也写过,之前是乘法和加法,这个是区间亦或和区间更新值,但是思路是可以借鉴的,我们要推出这两个操作的关系,这样才能维护好这两个标记,我们用两个标记:same , rev ,分别表

【线段树】HDU 3397 Sequence operation 区间合并

操作 Change operations: 0 a b change all characters into '0's in [a , b] 1 a b change all characters into '1's in [a , b] 2 a b change all '0's into '1's and change all '1's into '0's in [a, b] Output operations: 3 a b output the number of '1's in [a,

HDU 3397 Sequence operation(线段树)

HDU 3397 Sequence operation 题目链接 题意:给定一个01序列,有5种操作 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最长的长度 思路:线段树线段合并.须要两个延迟标记一个置为01,一个翻转,然后因为4操作,须要记录左边最长0.1.右边最长0.1,区间最长0.1,然后区间合并去搞就可以 代码: #include <cstdi

HDU 3397 Sequence operation 线段树

线段树大杂烩~ 各种操作都有,细心点不难1A #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; #define lson rt<<1,l,mid #define rson rt<<1|1,mid + 1,r const int maxn = 1e5 + 10; int lmax[maxn

HDU 3397 Sequence operation (线段树,成段更新,区间合并)

http://acm.hdu.edu.cn/showproblem.php?pid=3397 Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5801    Accepted Submission(s): 1713 Problem Description lxhgww got a sequence

HDU 3397 Sequence operation(线段树&#183;成段更新&#183;区间合并&#183;混合操作)

题意  给你一个只有0, 1的数组  有这些操作 0. 将[a, b]区间的所有数都改为0 1. 将[a, b]区间的所有数都改为1 2. 将[a, b]区间的所有数都取反 即与1异或 3. 输出区间[a, b]中1的个数  即所有数的和 4. 输出区间[a, b]中最大连续1的长度 对于所有的3, 4操作输出对应的答案 单个的操作都很简单  但搞在一起就有点恶心了  还好数组里的数只有0和1 线段树维护9个值 对应区间0, 1的最大长度len[i]  对应区间左端点为起点的最大0, 1长度ll

HDU 3397——Sequence operation(线段树,区间染色+区间异或+区间合并)

Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6270    Accepted Submission(s): 1862 Problem Description lxhgww got a sequence contains n characters which are all '0's or '1

Hdu 3397 Sequence operation(线段树多操作,Lazy思想,成段更新)

Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6397    Accepted Submission(s): 1899 Problem Description lxhgww got a sequence contains n characters which are all '0's or '1