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

Posted Pacify

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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,并将儿子的swp=0。如果swp=1,这里要注意一点,不是把儿子的swp赋值为1,而是与1异或!!!因为如果儿子的swp本为1,再互换一次,两个互换就相当于值没有变了。

注意下细节就行了

#include <bits/stdc++.h>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;

const int MAXN = 111111;

struct Node
{
    int num1, stv, swp;
    int mx0, lmx0, rmx0;
    int mx1, lmx1, rmx1;
} tr[MAXN<<2];

void changeto(int rt, int to,int len)
{
    tr[rt].mx0 = tr[rt].lmx0 = tr[rt].rmx0 = to? 0 : len;
    tr[rt].mx1 = tr[rt].lmx1 = tr[rt].rmx1 = tr[rt].num1 = to? len : 0;
}

void exchange(int rt, int len)
{
    tr[rt].num1 = len - tr[rt].num1;
    swap(tr[rt].mx0, tr[rt].mx1);
    swap(tr[rt].lmx0, tr[rt].lmx1);
    swap(tr[rt].rmx0, tr[rt].rmx1);
}

void push_down(int rt, int len)
{
    if(tr[rt].stv != -1)
    {
        tr[rt<<1].stv = tr[rt<<1|1].stv = tr[rt].stv;
        tr[rt<<1].swp = tr[rt<<1|1].swp = 0;
        changeto(rt<<1, tr[rt].stv, len-(len>>1));
        changeto(rt<<1|1, tr[rt].stv, len>>1);
        tr[rt].stv = -1;
    }
    if(tr[rt].swp == 1)
    {
        tr[rt<<1].swp ^= 1;
        tr[rt<<1|1].swp ^= 1;
        exchange(rt<<1, len-(len>>1));
        exchange(rt<<1|1, len>>1);
        tr[rt].swp = 0;
    }
}

void push_up(int rt, int len)
{
    tr[rt].num1 = tr[rt<<1].num1 + tr[rt<<1|1].num1;

    tr[rt].lmx0 = tr[rt<<1].lmx0;
    tr[rt].rmx0 = tr[rt<<1|1].rmx0;
    if(tr[rt].lmx0 == len - (len >> 1)) tr[rt].lmx0 += tr[rt<<1|1].lmx0;
    if(tr[rt].rmx0 == len >> 1) tr[rt].rmx0 += tr[rt<<1].rmx0;
    tr[rt].mx0 = max(tr[rt<<1].rmx0 + tr[rt<<1|1].lmx0, max(tr[rt<<1].mx0, tr[rt<<1|1].mx0));

    tr[rt].lmx1 = tr[rt<<1].lmx1;
    tr[rt].rmx1 = tr[rt<<1|1].rmx1;
    if(tr[rt].lmx1 == len - (len >> 1)) tr[rt].lmx1 += tr[rt<<1|1].lmx1;
    if(tr[rt].rmx1 == len >> 1) tr[rt].rmx1 += tr[rt<<1].rmx1;
    tr[rt].mx1 = max(tr[rt<<1].rmx1 + tr[rt<<1|1].lmx1, max(tr[rt<<1].mx1, tr[rt<<1|1].mx1));
}

void build(int l, int r, int rt)
{
    tr[rt].stv = -1;
    tr[rt].swp = 0;
    if(l == r)
    {
        scanf("%d", &tr[rt].num1);
        tr[rt].mx0 = tr[rt].lmx0 = tr[rt].rmx0 = tr[rt].num1 ^ 1;
        tr[rt].mx1 = tr[rt].lmx1 = tr[rt].rmx1 = tr[rt].num1;
        return;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    push_up(rt, r-l+1);
}

void update(int L, int R, int op, int l, int r, int rt)
{
    if(L <= l && r <= R)
    {
        if(op == 0 || op == 1)
        {
            changeto(rt, op, r-l+1);
            tr[rt].stv = op;
            tr[rt].swp = 0;
        }
        else
        {
            exchange(rt, r-l+1);
            tr[rt].swp ^= 1;
        }
        return;
    }
    push_down(rt, r-l+1);
    int m = (l + r) >> 1;
    if(m >= L) update(L, R, op, lson);
    if(m < R) update(L, R, op, rson);
    push_up(rt, r-l+1);
}

int query1(int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R) return tr[rt].num1;
    push_down(rt, r-l+1);
    int m = (l + r) >> 1;
    int ret = 0;
    if(m >= L) ret += query1(L, R, lson);
    if(m < R) ret += query1(L, R, rson);
    return ret;
}

int query2(int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R) return tr[rt].mx1;
    push_down(rt, r-l+1);
    int m = (l + r) >> 1;
    int ret = 0;
    if(m >= L) ret = max(ret, query2(L, R, lson));
    if(m < R) ret = max(ret, query2(L, R, rson));
    ret = max(ret, min(tr[rt<<1].rmx1, m-L+1) + min(tr[rt<<1|1].lmx1, R-m));
    return ret;
}

int main()
{
//    freopen("in.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        build(0, n-1, 1);
        while(m--)
        {
            int op, x, y;
            scanf("%d%d%d", &op, &x, &y);
            if(op <= 2) update(x, y, op, 0, n-1, 1);
            else if(op == 3) printf("%d\n", query1(x, y, 0, n-1, 1));
            else printf("%d\n", query2(x, y, 0, n-1, 1));
        }
    }
    return 0;
}

 

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

hdu-3397 Sequence operation 线段树多种标记

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

HDU 3397 Sequence operation 多标记线段树

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

HDU 3397 线段树区间修改

线段树 HDU 3397(真)