线段树 区间合并 F - Sequence operation

Posted echozqn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树 区间合并 F - Sequence operation相关的知识,希望对你有一定的参考价值。

F - Sequence operation

 

lxhgww got a sequence contains n characters which are all ‘0‘s or ‘1‘s. 
We have five operations here: 
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, b] 
4 a b output the length of the longest continuous ‘1‘ string in [a , b]
InputT(T<=10) in the first line is the case number. 
Each case has two integers in the first line: n and m (1 <= n , m <= 100000). 
The next line contains n characters, ‘0‘ or ‘1‘ separated by spaces. 
Then m lines are the operations: 
op a b: 0 <= op <= 4 , 0 <= a <= b < n.OutputFor each output operation , output the result.Sample Input
1
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
Sample Output
5
2
6
5




题解:
这个题目不是一个特别难的题目,但是呢,写了好久,首先线段树难敲,其次就是bug难找,最后这个代码都被我改的乱七八糟的了,
这个有两个地方要注意一下,一个是取反的lazy标志,每次取反都是对1取异或,还有一个也是这个取反的lazy标志,
这个标志再第一种操作之后要进行消除。


#include <cstdio>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <iostream>
#include <stack>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e6 + 100;
struct node
{
    int sum;
    int max_sub, max_zero;
    int l, r, len;
    int lazy1, lazy2;
    int max_prezero, max_lastzero;
    int max_preone, max_lastone;
}tree[maxn * 4];
int a[maxn];

void push_up(int id)
{
    tree[id].sum = tree[id << 1].sum + tree[id << 1 | 1].sum;

    tree[id].max_preone = tree[id << 1].max_preone;
    if (tree[id].max_preone == tree[id << 1].len)  tree[id].max_preone += tree[id << 1 | 1].max_preone;
    tree[id].max_lastone = tree[id << 1 | 1].max_lastone;
    if (tree[id].max_lastone == tree[id << 1 | 1].len)    tree[id].max_lastone += tree[id << 1].max_lastone;
    tree[id].max_sub = max(tree[id << 1].max_lastone + tree[id << 1 | 1].max_preone, max(tree[id << 1].max_sub, tree[id << 1 | 1].max_sub));

    tree[id].max_prezero = tree[id << 1].max_prezero;
    if (tree[id].max_prezero == tree[id << 1].len)    tree[id].max_prezero += tree[id << 1 | 1].max_prezero;
    tree[id].max_lastzero = tree[id << 1 | 1].max_lastzero;
    if (tree[id].max_lastzero == tree[id << 1 | 1].len)    tree[id].max_lastzero += tree[id << 1].max_lastzero;
    tree[id].max_zero = max(tree[id << 1].max_lastzero + tree[id << 1 | 1].max_prezero, max(tree[id << 1].max_zero, tree[id << 1 | 1].max_zero));

    return;
}

void chang1(int id, int val)
{
    if (val)
    {
        tree[id].sum = tree[id].len;
        tree[id].max_preone = tree[id].max_lastone = tree[id].max_sub = tree[id].len;
        tree[id].max_zero = tree[id].max_prezero = tree[id].max_lastzero = 0;
    }
    else
    {
        tree[id].sum = 0;
        tree[id].max_preone = tree[id].max_lastone = tree[id].max_sub = 0;
        tree[id].max_zero = tree[id].max_prezero = tree[id].max_lastzero = tree[id].len;
    }
}

void chang2(int id)
{
    swap(tree[id].max_sub, tree[id].max_zero);
    swap(tree[id].max_prezero, tree[id].max_preone);
    swap(tree[id].max_lastone, tree[id].max_lastzero);
    tree[id].sum = tree[id].len - tree[id].sum;
}

void push_down(int id)
{
    if (tree[id].lazy1)
    {
        chang1(id << 1, tree[id].lazy1 - 1);
        chang1(id << 1 | 1, tree[id].lazy1 - 1);
        tree[id << 1].lazy1 = tree[id << 1 | 1].lazy1 = tree[id].lazy1;
        tree[id << 1].lazy2 =tree[id << 1 | 1].lazy2 = 0;
        tree[id].lazy1 = 0;
    }
    if (tree[id].lazy2)
    {
        chang2(id << 1);
        chang2(id << 1 | 1);

        tree[id << 1].lazy2 ^= 1;
        tree[id << 1 | 1].lazy2 ^= 1;
        tree[id].lazy2 = 0;
    }
}

void build(int id, int l, int r)
{
    tree[id].l = l;
    tree[id].r = r;
    tree[id].lazy1 = 0;
    tree[id].lazy2 = 0;
    tree[id].len = r - l + 1;
    if (l == r)
    {
        if (a[l]) chang1(id, 1);
        else chang1(id, 0);
        return;
    }
    int mid = (l + r) >> 1;
    build(id << 1, l, mid);
    build(id << 1 | 1, mid + 1, r);
    push_up(id);
}

void update_change(int id, int l, int r, int z)
{
    if (l <= tree[id].l&&r >= tree[id].r)
    {
        chang1(id, z);
        tree[id].lazy1 = z + 1;
        tree[id].lazy2 = 0;
        return;
    }
    push_down(id);
    int mid = (tree[id].l + tree[id].r) >> 1;
    if (l <= mid) update_change(id << 1, l, r, z);
    if (r > mid) update_change(id << 1 | 1, l, r, z);
    push_up(id);
}

void update_trans(int id, int l, int r)
{
    if (l <= tree[id].l&&r >= tree[id].r)
    {
        tree[id].lazy2 ^= 1;
        chang2(id);
        return;
    }
    push_down(id);
    int mid = (tree[id].l + tree[id].r) >> 1;
    if (l <= mid) update_trans(id << 1, l, r);
    if (r > mid) update_trans(id << 1 | 1, l, r);
    push_up(id);
}

int query_sum(int id, int l, int r)
{
    if (l <= tree[id].l&&r >= tree[id].r)
    {
        return tree[id].sum;
    }
    push_down(id);
    int mid = (tree[id].l + tree[id].r) >> 1, ans = 0;
    if (l <= mid) ans += query_sum(id << 1, l, r);
    if (r > mid) ans += query_sum(id << 1 | 1, l, r);
    return ans;
}

int query(int id, int l, int r)
{
    int ans = 0;
    if (l <= tree[id].l&&r >= tree[id].r)
    {
        return tree[id].max_sub;
    }
    push_down(id);
    int mid = (tree[id].l + tree[id].r) >> 1;
    if (l <= mid) ans = max(ans, query(id << 1, l, r));
    if (r > mid) ans = max(ans, query(id << 1 | 1, l, r));
    ans = max(ans, min(mid - l + 1, tree[id << 1].max_lastone) + min(r - mid, tree[id << 1 | 1].max_preone));
    return ans;
}

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n, m;
        cin >> n >> m;
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        build(1, 1, n);
        while (m--)
        {
            int c, x, y;
            scanf("%d%d%d", &c, &x, &y);
            if (c == 0) update_change(1, x + 1, y + 1, 0);
            if (c == 1) update_change(1, x + 1, y + 1, 1);
            if (c == 2) update_trans(1, x + 1, y + 1);
            if (c == 3)
            {
                int ans = query_sum(1, x + 1, y + 1);
                printf("%d\n", ans);
            }
            if (c == 4)
            {
                int ans = query(1, x + 1, y + 1);
                printf("%d\n", ans);
            }
        }
    }
    return 0;
}

 









 

以上是关于线段树 区间合并 F - Sequence operation的主要内容,如果未能解决你的问题,请参考以下文章

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

HDU 3397 Sequence operation(线段树)

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

Sequence operation(线段树区间多种操作)

树套树

[HDU5306] Gorgeous Sequence - 线段树区间最值操作