P2572 [SCOI2010] 线段树

题意

传送门 P2572 [SCOI2010]序列操作

题解

操作 0 , 1 0,1 0,1 即简单的区间覆盖,操作 2 2 2 取反操作可以简单地交换区间内 0 , 1 0,1 0,1 的信息实现。需要维护的信息有区间 0 , 1 0,1 0,1 的总数、最大的连续长度、左连续的最大长度与右连续的最大长度。 l a z y   t a g lazy\ tag lazy tag 将区间修改复杂度降至 O ( l o g N ) O(logN) O(logN),使用多个 l a z y   t a g lazy\ tag lazy tag 时注意处理次序。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100005
#define t_size (1 << 18) - 1
struct node
{
    int tot[2], cnt[2], l[2], r[2];
} tree[t_size];
int N, M, A[maxn], lzf[t_size], lzr[t_size];

node merge(node &cl, node &cr, int ln, int rn)
{
    node p;
    for (int i = 0; i <= 1; i++)
    {
        p.tot[i] = cl.tot[i] + cr.tot[i];
        p.l[i] = cl.l[i] + (cl.l[i] == ln ? cr.l[i] : 0);
        p.r[i] = cr.r[i] + (cr.r[i] == rn ? cl.r[i] : 0);
        p.cnt[i] = max(max(cl.cnt[i], cr.cnt[i]), cl.r[i] + cr.l[i]);
    }
    return p;
}

inline void _swap(node &p)
{
    swap(p.tot[0], p.tot[1]);
    swap(p.cnt[0], p.cnt[1]);
    swap(p.l[0], p.l[1]);
    swap(p.r[0], p.r[1]);
}

inline void _op(int i, node &p, int l, int r)
{
    int j = i ^ 1;
    p.tot[i] = p.cnt[i] = p.l[i] = p.r[i] = r - l;
    p.tot[j] = p.cnt[j] = p.l[j] = p.r[j] = 0;
}

inline void pushdown(int k, int chl, int chr, int l, int r, int m)
{
    node &cl = tree[chl], &cr = tree[chr];
    if (lzf[k] != -1)
    {
        _op(lzf[k], cl, l, m);
        _op(lzf[k], cr, m, r);
        lzf[chl] = lzf[chr] = lzf[k];
        lzr[chl] = lzr[chr] = 0;
        lzf[k] = -1;
    }
    if (lzr[k])
    {
        _swap(cl);
        _swap(cr);
        lzr[chl] ^= 1, lzr[chr] ^= 1;
        lzr[k] = 0;
    }
}

void init(int k, int l, int r)
{
    if (r - l == 1)
    {
        node &p = tree[k];
        _op(A[l], p, l, r);
    }
    else
    {
        int chl = (k << 1) + 1, chr = (k << 1) + 2, m = (l + r) >> 1;
        init(chl, l, m);
        init(chr, m, r);
        tree[k] = merge(tree[chl], tree[chr], m - l, r - m);
    }
}

void update(int op, int a, int b, int k, int l, int r)
{
    node &p = tree[k];
    if (a <= l && r <= b)
    {
        if (op < 2)
        {
            lzf[k] = op, lzr[k] = 0;
            _op(op, p, l, r);
        }
        else
        {
            lzr[k] ^= 1;
            _swap(p);
        }
    }
    else if (a < r && l < b)
    {
        int chl = (k << 1) + 1, chr = (k << 1) + 2, m = (l + r) >> 1;
        pushdown(k, chl, chr, l, r, m);
        update(op, a, b, chl, l, m);
        update(op, a, b, chr, m, r);
        tree[k] = merge(tree[chl], tree[chr], m - l, r - m);
    }
}

node query(int a, int b, int k, int l, int r)
{
    if (a <= l && r <= b)
        return tree[k];
    int chl = (k << 1) + 1, chr = (k << 1) + 2, m = (l + r) >> 1;
    pushdown(k, chl, chr, l, r, m);
    if (b <= m)
        return query(a, b, chl, l, m);
    if (m <= a)
        return query(a, b, chr, m, r);
    node p1 = query(a, b, chl, l, m), p2 = query(a, b, chr, m, r);
    return merge(p1, p2, m - max(a, l), min(b, r) - m);
}

int main()
{
    scanf("%d%d", &N, &M);
    for (int i = 0; i < N; i++)
        scanf("%d", A + i);
    init(0, 0, N);
    memset(lzf, -1, sizeof(lzf));
    memset(lzr, 0, sizeof(lzr));
    while (M--)
    {
        int op, a, b;
        scanf("%d%d%d", &op, &a, &b);
        if (op <= 2)
            update(op, a, b + 1, 0, 0, N);
        else
        {
            node p = query(a, b + 1, 0, 0, N);
            printf("%d\n", op == 3 ? p.tot[1] : p.cnt[1]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值