线段树/lazy技巧(HDU - 3397 Sequence operation)

题目链接
普通线段树,只不过要维护的东西有点多:

struct Node
{
    int l, r;
    int sum0, sum1;//0,1的总和
    bool flag0;//全0标记
    bool flag1;//全1标记
    int add;//操作延迟标记
    int sumc0;//最长连续0长度
    int sumc1;//最长连续1长度
    int ls1, rs1;//最长连续1前、后缀
    int ls0, rs0;//最长连续0前、后缀
}tr[N<<2];

重点对于add的维护。我们设:

add == -1 无操作 add == 0 全变0操作
add == 1 全变1操作 add == 2 异或操作

我们把k操作覆盖在p节点上,可以执行:

void update(int p, int k)
{
    if (k != 2)
    {//全1,全0,直接覆盖
        tr[p].sum0 = tr[p].sumc0 = tr[p].ls0 = tr[p].rs0 = !k*(tr[p].r - tr[p].l +1);
        tr[p].add = k;
        tr[p].flag0 = !k;
        tr[p].sum1 = tr[p].sumc1 = tr[p].ls1 = tr[p].rs1 = k*(tr[p].r - tr[p].l +1);
        tr[p].flag1 = k;
    }
    else
    {//对于异或操作的附加:
    //2->-1 == 2;  2->0 == 1;
    //2-> 1 == 0; 2->2 == -1;
        tr[p].add = 1 - tr[p].add;//总结下来就是这个。
        swap(tr[p].flag0, tr[p].flag1);
        swap(tr[p].sum0, tr[p].sum1);
        swap(tr[p].sumc0, tr[p].sumc1);
        swap(tr[p].ls0, tr[p].ls1);
        swap(tr[p].rs0, tr[p].rs1);//其余交换
    }
}

于是本题得以解出。
下面是ac代码:

#include <iostream>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <algorithm>
#include <cstdlib>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
const ll inf = 1e16;
int su[N];
struct Node
{
    int l, r;
    int sum0, sum1;
    bool flag0;
    bool flag1;
    int add;
    int sumc0;
    int sumc1;
    int ls1, rs1;
    int ls0, rs0;
}tr[N<<2];
void update(int p, int k)
{
    if (k != 2)
    {
        tr[p].sum0 = tr[p].sumc0 = tr[p].ls0 = tr[p].rs0 = !k*(tr[p].r - tr[p].l +1);
        tr[p].add = k;
        tr[p].flag0 = !k;
        tr[p].sum1 = tr[p].sumc1 = tr[p].ls1 = tr[p].rs1 = k*(tr[p].r - tr[p].l +1);
        tr[p].flag1 = k;
    }
    else
    {
        tr[p].add = 1 - tr[p].add;
        swap(tr[p].flag0, tr[p].flag1);
        swap(tr[p].sum0, tr[p].sum1);
        swap(tr[p].sumc0, tr[p].sumc1);
        swap(tr[p].ls0, tr[p].ls1);
        swap(tr[p].rs0, tr[p].rs1);
    }
}
void spread(int p)
{
    if (tr[p].add == -1) return;
    update(p<<1, tr[p].add);
    update(p<<1|1, tr[p].add);
    tr[p].add = -1;
}
void pushup(int p)
{
    int l = p<<1, r = p<<1|1;
    tr[p].flag0 = tr[l].flag0 && tr[r].flag0;
    tr[p].flag1 = tr[l].flag1 && tr[r].flag1;
    tr[p].sum0 = tr[l].sum0 + tr[r].sum0;
    tr[p].sum1 = tr[l].sum1 + tr[r].sum1;
    tr[p].sumc1 = max(tr[l].rs1+tr[r].ls1, max(tr[l].sumc1, tr[r].sumc1));
    tr[p].sumc0 = max(tr[l].rs0+tr[r].ls0, max(tr[l].sumc0, tr[r].sumc0));
    tr[p].ls1 = tr[l].flag1?tr[l].sum1+tr[r].ls1:tr[l].ls1;
    tr[p].ls0 = tr[l].flag0?tr[l].sum0+tr[r].ls0:tr[l].ls0;
    tr[p].rs1 = tr[r].flag1?tr[r].sum1+tr[l].rs1:tr[r].rs1;
    tr[p].rs0 = tr[r].flag0?tr[r].sum0+tr[l].rs0:tr[r].rs0;
}
void build(int p, int l, int r)
{
    tr[p].l = l; tr[p].r = r;
    tr[p].add = -1;
    if (l == r)
    {
        tr[p].sumc1 = tr[p].ls1 = tr[p].rs1 = tr[p].sum1 = su[l];
        tr[p].flag1 = su[l];
        tr[p].sumc0 = tr[p].ls0 = tr[p].rs0 = tr[p].sum0 = !su[l];
        tr[p].flag0 = !su[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(p<<1, l, mid);
    build(p<<1|1, mid+1, r);
    pushup(p);
}
void change(int p, int l, int r, int k)
{
    if (l <= tr[p].l && tr[p].r <= r)
    {
        update(p, k);
        return;
    }
    spread(p);
    int mid = (tr[p].l + tr[p].r) >> 1;
    if (l <= mid) change(p<<1, l, r, k);
    if (r > mid) change(p<<1|1, l, r, k);
    pushup(p);
}
int ask_n(int p, int l, int r)
{
    if (l <= tr[p].l && tr[p].r <= r)
        return tr[p].sum1;
    spread(p);
    int mid = (tr[p].l + tr[p].r) >> 1;
    int val = 0;
    if (l <= mid) val += ask_n(p<<1, l, r);
    if (r > mid) val += ask_n(p<<1|1, l, r);
    return val;
}
Node ask_c(int p, int l, int r)
{
    if (l <= tr[p].l && tr[p].r <= r)
        return tr[p];
    spread(p);
    int mid = (tr[p].l + tr[p].r) >> 1;
    Node _l, _r;
    if (l > mid)
        return ask_c(p<<1|1, l, r);
    else if (r <= mid)
        return ask_c(p<<1, l, r);
    _l = ask_c(p<<1, l, r);
    _r = ask_c(p<<1|1, l, r);
    Node te;
    te.sumc1 = max(_l.rs1+_r.ls1, max(_l.sumc1, _r.sumc1));
    te.ls1 = _l.flag1?_l.sum1+_r.ls1:_l.ls1;
    te.rs1 = _r.flag1?_r.sum1+_l.rs1:_r.rs1;
    return te;
}
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i++)
            scanf("%d", &su[i]);
        build(1, 0, n-1);
        while(m--)
        {
            int op;
            int l, r;
            scanf("%d%d%d", &op, &l, &r);
            if(op == 0)
                change(1, l, r, 0);
            if (op == 1)
                change(1, l, r, 1);
            if (op == 2)
                change(1, l, r, 2);
            if (op == 3)
                printf("%d\n", ask_n(1, l, r));
            if (op == 4)
            {
               Node te = ask_c(1, l, r);
               printf("%d\n", te.sumc1);
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值