hdu 3397 Sequence operation(线段树:区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 

题意:给你一个长度为n的0,1序列,支持下列五种操作,

操作0(0 a b):将a到b这个区间的元素全部置为0。

操作1(1 a b):将a到b这个区间的元素全部置为1。

操作2(2 a b):将a到b这个区间所有的0置为1,所有的1置为0。

操作3(3 a b):查询a到b这个区间1的总数。

操作4(4 a b):查询a到b这个区间连续1的最长长度

本题属于简单的区间更新线段树

重点:0操作和1操作都属于普通的set操作,可以直接覆盖其他操作,但是2操作需要仔细考虑。操作2在其他的操作之后不能直接采用覆盖的方式,比如(1 left right) (2 left right)的操作序列,如果直接覆盖就变成了(2 left right),而实际上应该变成(0 left right)。大家可以看下代码中的deal_xor函数。

感想:主啊,眼睛都快敲瞎了,敲完还一直wrong,瞬间??。

#include <iostream>
#include <cstring>
#include <algorithm>
#define maxn 400010
#define inf 1000000000
#define LL(x) x<<1
#define RR(x) x<<1|1
using namespace std;

typedef long long LL;

//variable define

struct tree
{
    int l, r;
    int cnt;
    int lsum0, rsum0, sum0;
    int lsum1, rsum1, sum1;
    int set;
};

tree node[maxn];
int n, m;

//function define

void push_down(int x);

void push_up(int x);

void build_tree(int left, int right, int x);

tree query(int left, int right, int x);

void update_set(int left, int right, int x, int val);

int deal_xor(int x)
{
    if (node[x].set == -1)
        return 2;
    else if (node[x].set == 0)
        return 1;
    else if (node[x].set == 1)
        return 0;
    else
        return -1;
}

int main(void)
{
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        scanf("%d %d", &n, &m);
        build_tree( 1, n, 1);
        int op, x, y;
        while (m--)
        {
            scanf("%d %d %d", &op, &x, &y);
            x += 1;
            y += 1;
            if (op == 0)
            {
                update_set( x, y, 1, op);
            }
            else if (op == 1)
            {
                update_set( x, y, 1, op);
            }
            else if (op == 2)
            {
                update_set( x, y, 1, op);
            }
            else if (op == 3)
            {
                tree result = query( x, y, 1);
                printf("%d\n", result.cnt);
            }
            else
            {
                tree result = query( x, y, 1);
                printf("%d\n", result.sum1);
            }
        }
    }
    return 0;
}

void build_tree(int left, int right, int x)
{
    node[x].l = left;
    node[x].r = right;
    node[x].set = -1;
    if (left == right)
    {
        int t;
        scanf("%d", &t);
        if (t == 1)
        {
            node[x].cnt = node[x].sum1 = node[x].lsum1 = node[x].rsum1 = 1;
            node[x].sum0 = node[x].lsum0 = node[x].rsum0 = 0;

        }
        else
        {
            node[x].cnt = node[x].sum1 = node[x].lsum1 = node[x].rsum1 = 0;
            node[x].sum0 = node[x].lsum0 = node[x].rsum0 = 1;
        }
        return;
    }

    int lx = LL(x);
    int rx = RR(x);
    int mid = left + (right - left)/2;
    build_tree(left, mid, lx);
    build_tree(mid + 1, right, rx);
    push_up(x);
}

void push_up(int x)
{
    if (node[x].l >= node[x].r)
        return;

    int lx = LL(x);
    int rx = RR(x);
    node[x].cnt = node[lx].cnt + node[rx].cnt;
    node[x].sum1 = max( node[lx].rsum1 + node[rx].lsum1, max( node[lx].sum1, node[rx].sum1));
    node[x].lsum1 = node[lx].lsum1 == (node[lx].r - node[lx].l + 1) ? node[lx].lsum1 + node[rx].lsum1 : node[lx].lsum1;
    node[x].rsum1 = node[rx].rsum1 == (node[rx].r - node[rx].l + 1) ? node[rx].rsum1 + node[lx].rsum1 : node[rx].rsum1;
    node[x].sum0 = max( node[lx].rsum0 + node[rx].lsum0, max( node[lx].sum0, node[rx].sum0));
    node[x].lsum0 = node[lx].lsum0 == (node[lx].r - node[lx].l + 1) ? node[lx].lsum0 + node[rx].lsum0 : node[lx].lsum0;
    node[x].rsum0 = node[rx].rsum0 == (node[rx].r - node[rx].l + 1) ? node[rx].rsum0 + node[lx].rsum0 : node[rx].rsum0;
}

void push_down(int x)
{
    if (node[x].l >= node[x].r)
        return;
    int lx = LL(x);
    int rx = RR(x);
    if (node[x].set != -1)
    {
        if (node[x].set == 0)
        {
            node[lx].cnt = node[lx].sum1 = node[lx].lsum1 = node[lx].rsum1 = 0;
            node[lx].sum0 = node[lx].lsum0 = node[lx].rsum0 = node[lx].r - node[lx].l + 1;
            node[rx].cnt = node[rx].sum1 = node[rx].lsum1 = node[rx].rsum1 = 0;
            node[rx].sum0 = node[rx].lsum0 = node[rx].rsum0 = node[rx].r - node[rx].l + 1;
            node[lx].set = node[rx].set = 0;
        }
        else if (node[x].set == 1)
        {
            node[lx].cnt = node[lx].sum1 = node[lx].lsum1 = node[lx].rsum1 = node[lx].r - node[lx].l + 1;
            node[lx].sum0 = node[lx].lsum0 = node[lx].rsum0 = 0;
            node[rx].cnt = node[rx].sum1 = node[rx].lsum1 = node[rx].rsum1 = node[rx].r - node[rx].l + 1;
            node[rx].sum0 = node[rx].lsum0 = node[rx].rsum0 = 0;
            node[lx].set = node[rx].set = 1;
        }
        else
        {
            int t1, t2, t3;
            node[lx].set = deal_xor(lx);
            node[lx].cnt = node[lx].r - node[lx].l + 1 - node[lx].cnt;
            t1 = node[lx].sum1;
            t2 = node[lx].lsum1;
            t3 = node[lx].rsum1;
            node[lx].sum1 = node[lx].sum0;
            node[lx].lsum1 = node[lx].lsum0;
            node[lx].rsum1 = node[lx].rsum0;
            node[lx].sum0 = t1;
            node[lx].lsum0 = t2;
            node[lx].rsum0 = t3;

            node[rx].set = deal_xor(rx);
            node[rx].cnt = node[rx].r - node[rx].l + 1 - node[rx].cnt;
            t1 = node[rx].sum1;
            t2 = node[rx].lsum1;
            t3 = node[rx].rsum1;
            node[rx].sum1 = node[rx].sum0;
            node[rx].lsum1 = node[rx].lsum0;
            node[rx].rsum1 = node[rx].rsum0;
            node[rx].sum0 = t1;
            node[rx].lsum0 = t2;
            node[rx].rsum0 = t3;
        }
    }
}

void update_set(int left, int right, int x, int val)
{
    if (node[x].l == left && node[x].r == right)
    {
        if (val == 0)
        {
            node[x].cnt = node[x].sum1 = node[x].lsum1 = node[x].rsum1 = 0;
            node[x].sum0 = node[x].lsum0 = node[x].rsum0 = node[x].r - node[x].l + 1;
            node[x].set = 0;
        }
        else if (val == 1)
        {
            node[x].cnt = node[x].sum1 = node[x].lsum1 = node[x].rsum1 = node[x].r - node[x].l + 1;
            node[x].sum0 = node[x].lsum0 = node[x].rsum0 = 0;
            node[x].set = 1;
        }
        else
        {
            node[x].set = deal_xor(x);
            node[x].cnt = node[x].r - node[x].l + 1 - node[x].cnt;
            int t1, t2, t3;
            t1 = node[x].sum1;
            t2 = node[x].lsum1;
            t3 = node[x].rsum1;
            node[x].sum1 = node[x].sum0;
            node[x].lsum1 = node[x].lsum0;
            node[x].rsum1 = node[x].rsum0;
            node[x].sum0 = t1;
            node[x].lsum0 = t2;
            node[x].rsum0 = t3;
        }
        return;
    }
    push_down(x);
    node[x].set = -1;
    int lx = LL(x);
    int rx = RR(x);
    int mid = node[x].l + (node[x].r - node[x].l)/2;
    if (right <= mid)
        update_set(left, right, lx, val);
    else if (left > mid)
        update_set(left, right, rx, val);
    else
    {
        update_set(left, mid, lx, val);
        update_set(mid + 1, right, rx, val);
    }
    push_up( x);
}

tree query(int left, int right, int x)
{
    if (node[x].l == left && node[x].r == right)
    {
        return node[x];
    }
    push_down(x);
    node[x].set = -1;
    int mid = node[x].l + (node[x].r - node[x].l)/2;
    int lx = LL(x);
    int rx = RR(x);
    tree ans;
    if (right <= mid)
        ans = query(left, right, lx);
    else if (left > mid)
        ans = query(left, right, rx);
    else
    {
        tree lnode = query(left, mid, lx);
        tree rnode = query(mid + 1, right, rx);
        ans.cnt = lnode.cnt + rnode.cnt;
        ans.sum1 = max( lnode.rsum1 + rnode.lsum1, max( lnode.sum1, rnode.sum1));
        ans.lsum1 = lnode.lsum1 == (lnode.r - lnode.l + 1) ? lnode.lsum1 + rnode.lsum1 : lnode.lsum1;
        ans.rsum1 = rnode.rsum1 == (rnode.r - rnode.l + 1) ? rnode.rsum1 + lnode.rsum1 : rnode.rsum1;
        ans.sum0 = max( lnode.rsum0 + rnode.lsum0, max( lnode.sum0, rnode.sum0));
        ans.lsum0 = lnode.lsum0 == (lnode.r - lnode.l + 1) ? lnode.lsum0 + rnode.lsum0 : lnode.lsum0;
        ans.rsum0 = rnode.rsum0 == (rnode.r - rnode.l + 1) ? rnode.rsum0 + lnode.rsum0 : rnode.rsum0;
    }
    push_up(x);
    return ans;
}
时间: 2024-10-13 21:24:55

hdu 3397 Sequence operation(线段树:区间更新)的相关文章

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,并将儿子的sw

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

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意: 给你一串01串,有5种操作 0. 区间全部变为0 1.区间全部变为1 2.区间异或 3.询问区间1的个数 4.询问区间被最长连续1的长度 思路: 这5个操作都是比较基础的线段树操作,难点在于有两种修改操作,这类题之前也写过,之前是乘法和加法,这个是区间亦或和区间更新值,但是思路是可以借鉴的,我们要推出这两个操作的关系,这样才能维护好这两个标记,我们用两个标记:same , rev ,分别表

HDU 3397 Sequence operation 线段树

线段树大杂烩~ 各种操作都有,细心点不难1A #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; #define lson rt<<1,l,mid #define rson rt<<1|1,mid + 1,r const int maxn = 1e5 + 10; int lmax[maxn

HDU 3397 Sequence operation (线段树,成段更新,区间合并)

http://acm.hdu.edu.cn/showproblem.php?pid=3397 Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5801    Accepted Submission(s): 1713 Problem Description lxhgww got a sequence

Hdu 3397 Sequence operation(线段树多操作,Lazy思想,成段更新)

Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6397    Accepted Submission(s): 1899 Problem Description lxhgww got a sequence contains n characters which are all '0's or '1

HDU 3577 Fast Arrangement (线段树区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3577 题意不好理解,给你数字k表示这里车最多同时坐k个人,然后有q个询问,每个询问是每个人的上车和下车时间,每个人按次序上车,问哪些人能上车输出他们的序号. 这题用线段树的成段更新,把每个人的上下车时间看做一个线段,每次上车就把这个区间都加1,但是上车的前提是这个区间上的最大值不超过k.有个坑点就是一个人上下车的时间是左闭右开区间,可以想到要是一个人下车,另一个人上车,这个情况下这个点的大小还是不变

HDU 4902 Nice boat --线段树(区间更新)

题意:给一个数字序列,第一类操作是将[l,r]内的数全赋为x ,第二类操作是将[l,r]中大于x的数赋为该数与x的gcd,若干操作后输出整个序列. 解法: 本题线段树要维护的最重要的东西就是一个区间内所有数是否相等的标记.只维护这个东西都可以做出来. 我当时想歪了,想到维护Max[rt]表示该段的最大值,最大值如果<=x的话就不用更新了,但是好像加了这个“优化”跑的更慢了. 我想大概是因为如果两个子树最大值或者整个两个子树的数不完全相等的话,根本不能直接下传这个值或者下传gcd,因为你不知道要更

hdu 1698+poj 3468 (线段树 区间更新)

http://acm.hdu.edu.cn/showproblem.php?pid=1698 这个题意翻译起来有点猥琐啊,还是和谐一点吧 和涂颜色差不多,区间初始都为1,然后操作都是将x到y改为z,注意 是改为z,不是加或减,最后输出区间总值 也是线段树加lazy操作 1 #include<cstdio> 2 using namespace std; 3 struct point { 4 int l,r; 5 int val,sum; 6 }; 7 point tree[400007]; 8

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

Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7452    Accepted Submission(s): 2220 Problem Description lxhgww got a sequence contains n characters which are all '0's or '1

【线段树】HDU 3397 Sequence operation 区间合并

操作 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,