HDU 3397(线段树)

Problem Description

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]

 

 

Input

T(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.

 

找了我一天的bug,终于找出来的。。。

下面讲一下思路,我们把操作0和1称为覆盖操作,若某区间执行了这两者之一的操作,则清楚该区间所有其他标记,若执行0,1替换操作,这里是重点,因为这个我找了一天的bug。。。若同一个区间连续进行两次交换操作,则要把这个区间的交换的lazy标记去掉。

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#define LL long long
using namespace std;
const int MAX = 1e5 + 50;

struct date
{
    int len; // 记录区间长度
    int ln, rn; // 记录区间左端和右端的数字
    int ls0, rs0, ms0; //记录区间从左开始的最长连续0,右端开始的最长连续0,以及区间的最长连续0
    int ls1, rs1, ms1; //同上
    int sum1; //记录1的个数
} tree[MAX << 2]; // 线段树

int a[MAX]; //原数组
int lazy[MAX << 2][3]; // 0代表操作0,类推

void PushUp(int rt){ 
    int li = rt << 1;
    int ri = rt << 1 | 1;
    tree[rt].ln = tree[li].ln;
    tree[rt].rn = tree[ri].rn;
    tree[rt].ls1 = tree[li].ls1;
    tree[rt].rs1 = tree[ri].rs1;
    tree[rt].ms1 = max(tree[li].ms1, tree[ri].ms1);
    tree[rt].ls0 = tree[li].ls0;
    tree[rt].rs0 = tree[ri].rs0;
    tree[rt].ms0 = max(tree[li].ms0, tree[ri].ms0);
    tree[rt].sum1 = tree[li].sum1 + tree[ri].sum1;

    if(tree[li].rn == tree[ri].ln){
        if(tree[li].rn == 0){
            if(tree[li].len == tree[li].ls0){
                tree[rt].ls0 = tree[li].ls0 + tree[ri].ls0;
            }
            if(tree[ri].len == tree[ri].rs0){
                tree[rt].rs0 = tree[ri].rs0 + tree[li].rs0;
            }
            tree[rt].ms0 = max(tree[rt].ms0, tree[li].rs0 + tree[ri].ls0);
        } else{
            if(tree[li].len == tree[li].ls1){
                tree[rt].ls1 = tree[li].ls1 + tree[ri].ls1;
            }
            if(tree[ri].len == tree[ri].rs1){
                tree[rt].rs1 = tree[ri].rs1 + tree[li].rs1;
            }
            tree[rt].ms1 = max(tree[rt].ms1, tree[li].rs1 + tree[ri].ls1);
        }
    }
}

void Build(int l, int r, int rt){
    tree[rt].len = r - l + 1;
    if(l == r){
        tree[rt].ln = tree[rt].rn = a[l];
        if(a[l] == 0){
            tree[rt].ls0 = tree[rt].rs0 = tree[rt].ms0 = 1;
            tree[rt].ls1 = tree[rt].rs1 = tree[rt].ms1 = 0;
            tree[rt].sum1 = 0;
        } else{
            tree[rt].ls0 = tree[rt].rs0 = tree[rt].ms0 = 0;
            tree[rt].ls1 = tree[rt].rs1 = tree[rt].ms1 = 1;
            tree[rt].sum1 = 1;
        }
        return ;
    }

    int m = (l + r) >> 1;
    Build(l, m, rt << 1);
    Build(m + 1, r, rt << 1 | 1);
    PushUp(rt);
}

void PushDown(int rt){
    if(tree[rt].len == 1){
        return ;
    }
    int li = rt << 1;
    int ri = rt << 1 | 1;
    if(lazy[rt][0]){
        lazy[rt][0] = 0;
        tree[ri].ls0 = tree[ri].rs0 = tree[ri].ms0 = tree[ri].len;
        tree[ri].ls1 = tree[ri].rs1 = tree[ri].ms1 = 0;
        tree[ri].ln = tree[ri].rn = 0;
        tree[ri].sum1 = 0;
        lazy[ri][0] = 1; // 要把除了操作0的其他lazy标记去除
        lazy[ri][1] = 0;
        lazy[ri][2] = 0;
        tree[li].ls0 = tree[li].rs0 = tree[li].ms0 = tree[li].len;
        tree[li].ls1 = tree[li].rs1 = tree[li].ms1 = 0;
        tree[li].ln = tree[li].rn = 0;
        tree[li].sum1 = 0;
        lazy[li][0] = 1;
        lazy[li][1] = 0;
        lazy[li][2] = 0;
    }
    if(lazy[rt][1]){
        lazy[rt][1] = 0;
        tree[ri].ls0 = tree[ri].rs0 = tree[ri].ms0 = 0;
        tree[ri].ls1 = tree[ri].rs1 = tree[ri].ms1 = tree[ri].len;
        tree[ri].ln = tree[ri].rn = 1;
        tree[ri].sum1 = tree[ri].len;
        lazy[ri][0] = 0;// 要把除了操作1的其他lazy标记去除
        lazy[ri][1] = 1;
        lazy[ri][2] = 0;
        tree[li].ls0 = tree[li].rs0 = tree[li].ms0 = 0;
        tree[li].ls1 = tree[li].rs1 = tree[li].ms1 = tree[li].len;
        tree[li].ln = tree[li].rn = 1;
        tree[li].sum1 = tree[li].len;
        lazy[li][0] = 0;
        lazy[li][1] = 1;
        lazy[li][2] = 0;
    }

    if(lazy[rt][2]){
        lazy[rt][2] = 0;
        swap(tree[li].ls0, tree[li].ls1);
        swap(tree[li].rs0, tree[li].rs1);
        swap(tree[li].ms0, tree[li].ms1);
        tree[li].sum1 = tree[li].len - tree[li].sum1;
        tree[li].ln ^= 1;
        tree[li].rn ^= 1;
        lazy[li][2] ^= 1; // 这里也对1异或,理由就像之前讲的
        swap(tree[ri].ls0, tree[ri].ls1);
        swap(tree[ri].rs0, tree[ri].rs1);
        swap(tree[ri].ms0, tree[ri].ms1);
        tree[ri].sum1 = tree[ri].len - tree[ri].sum1;
        tree[ri].ln ^= 1;
        tree[ri].rn ^= 1;
        lazy[ri][2] ^= 1;
    }
}

int L, R;
void Update0(int l, int r, int rt){
    if(L <= l && r <= R){
        tree[rt].ls0 = tree[rt].rs0 = tree[rt].ms0 = tree[rt].len;
        tree[rt].ls1 = tree[rt].rs1 = tree[rt].ms1 = 0;
        tree[rt].ln = tree[rt].rn = 0;
        tree[rt].sum1 = 0;
        lazy[rt][0] = 1;
        lazy[rt][1] = 0;
        lazy[rt][2] = 0;
        return ;
    }

    PushDown(rt);
    int m = (l + r) >> 1;
    if(L <= m){
        Update0(l, m, rt << 1);
    }
    if(R > m){

        Update0(m + 1, r, rt << 1 | 1);
    }
    PushUp(rt);
}

void Update1(int l, int r, int rt){
    if(L <= l && r <= R){
        tree[rt].ls0 = tree[rt].rs0 = tree[rt].ms0 = 0;
        tree[rt].ls1 = tree[rt].rs1 = tree[rt].ms1 = tree[rt].len;
        tree[rt].ln = tree[rt].rn = 1;
        tree[rt].sum1 = tree[rt].len;
        lazy[rt][0] = 0;
        lazy[rt][1] = 1;
        lazy[rt][2] = 0;
        return ;
    }

    PushDown(rt);
    int m = (l + r) >> 1;
    if(L <= m){
        Update1(l, m, rt << 1);
    }
    if(R > m){

        Update1(m + 1, r, rt << 1 | 1);
    }
    PushUp(rt);
}

void Update2(int l, int r, int rt){
    if(L <= l && r <= R){
        swap(tree[rt].ls0, tree[rt].ls1);
        swap(tree[rt].rs0, tree[rt].rs1);
        swap(tree[rt].ms0, tree[rt].ms1);
        tree[rt].sum1 = tree[rt].len - tree[rt].sum1;
        tree[rt].ln ^= 1;
        tree[rt].rn ^= 1;
        lazy[rt][2] ^= 1; //这里对1异或,理由同上
        return ;
    }

    PushDown(rt);
    int m = (l + r) >> 1;
    if(L <= m){
        Update2(l, m, rt << 1);
    }
    if(R > m){
        Update2(m + 1, r, rt << 1 | 1);
    }
    PushUp(rt);
}

int Query3(int l, int r, int rt){
    if(L <= l && r <= R){
        return tree[rt].sum1;
    }
    int ans = 0;
    PushDown(rt);
    int m = (l + r) >> 1;
    if(L <= m){
        ans += Query3(l, m, rt << 1);
    }
    if(R > m){
        ans += Query3(m + 1, r, rt << 1 | 1);
    }
    return ans;
}

int Query4(int l, int r, int rt){
    if(L <= l && r <= R){
        return tree[rt].ms1;
    }
    PushDown(rt);
    int m = (l + r) >> 1;
    if(R <= m){
        return Query4(l, m, rt << 1);
    }
    if(L > m){
        return Query4(m + 1, r, rt << 1 | 1);
    }

    int t1 = Query4(l, m, rt << 1);
    int t2 = Query4(m + 1, r, rt << 1 | 1);
    int t3 = 0;
    int li = rt << 1;
    int ri = rt << 1 | 1;
    if(tree[li].rn == tree[ri].ln && tree[li].rn){
        t3 = min(m - L + 1, tree[li].rs1) + min(R - m, tree[ri].ls1);
    }
    return max(max(t1, t2), t3);
}

int main(int argc, char const *argv[])
{
    int t;
    scanf("%d", &t);
    while(t--){
        memset(lazy, 0, sizeof(lazy));
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
        }
        Build(1, n, 1);

        while(m--){
            int q;
            scanf("%d%d%d", &q, &L, &R);
            L++; //题目给的区间时从0开始的,为了方便我们从1开始,所以这里要++
            R++;
            if(q == 0){
                Update0(1, n, 1);
            } else if(q == 1){
                Update1(1, n, 1);
            } else if(q == 2){
                Update2(1, n, 1);
            } else if(q == 3){
                printf("%d\n", Query3(1, n, 1));
            } else{
                printf("%d\n", Query4(1, n, 1));
            }
        }
    }
    return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值