线段树 HDU 3397 Sequence operation

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

代码风格:http://www.notonlysuccess.com/index.php/segment-tree-complete/


题目大意:操作说明:0——把[a,b]区间全部变成0;1——把[a, b]区间全部变成1;2——把[a,b]区间0,1取反;3——输出[a,b]区间1的个数;4——输出[a, b]区间最长连续1的长度

算法:线段树 区间合并

思路:0,1 操作如果不会可以去做一下POJ3367,代码见http://www.notonlysuccess.com/index.php/segment-tree-complete/

同时统计0和1的左边连续个数lsun,lsum,右边连续个数rsun,rsum,区间最长连续个数msun,msum以及区间内1的个数p

0,1操作时,把取反标记清零

2操作:建立数组x[]作为取反标记,并且lsum,rsun互换,rsum,rsun互换,msum, msun互换,p改变

#include"cstdio"
#include"cstring"
#include"cmath"
#include"algorithm"
using namespace std;

const int Max = 444444;
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1 | 1
#define mid int m  = (l+r) >> 1

int lsun[Max], rsun[Max], msun[Max];
int rsum[Max], lsum[Max], msum[Max];
int cover[Max], p[Max], x[Max];

void fxor(int rt)
{
    if(cover[rt] != -1)
        cover[rt] ^= 1;
    else x[rt] ^= 1;
}

int max(int a, int b)
{
    return a > b ? a : b;
}

int min(int a, int b)
{
    return a < b ? a : b;
}

void PushUp(int l, int r, int rt, int m)
{
    //printf("%d -- %d, rt == %d\n", p[rt << 1 ], p[rt << 1 | 1], rt);
    p[rt] = p[rt << 1 ] + p[rt << 1 | 1];
    rsum[rt] = rsum[rt << 1 | 1];
    rsun[rt] = rsun[rt << 1 | 1];
    lsum[rt] = lsum[rt << 1];
    lsun[rt] = lsun[rt << 1];
    if(lsun[rt] == m - (m >> 1))
        lsun[rt] += lsun[rt << 1 | 1];
    if(lsum[rt] == m - (m >> 1))
        lsum[rt] += lsum[rt << 1 | 1];
    if(rsun[rt] == m >> 1)
        rsun[rt] += rsun[rt << 1];
    if(rsum[rt] == m >> 1)
        rsum[rt] += rsum[rt << 1];
    msum[rt] = max(max(msum[rt << 1], msum[rt << 1 | 1]), lsum[rt << 1 | 1] + rsum[rt << 1]);
    msun[rt] = max(max(msun[rt << 1], msun[rt << 1 | 1]), lsun[rt << 1 | 1] + rsun[rt << 1 ]);
}

void PushDown(int rt, int m)
{
    if(cover[rt] != -1)
    {
        cover[rt << 1] = cover[rt << 1 | 1] = cover[rt];
        msum[rt << 1] = rsum[rt << 1] = lsum[rt << 1] = p[rt << 1] = cover[rt] * (m - (m >> 1));
        msum[rt << 1 | 1] = rsum[rt << 1 | 1] = lsum[rt << 1 | 1] = p[rt << 1 | 1] = cover[rt] * (m >> 1);
        msun[rt << 1] = rsun[rt << 1] = lsun[rt << 1] = cover[rt] ? 0 : m - (m >> 1);
        msun[rt << 1 | 1] = rsun[rt << 1 | 1] = lsun[rt << 1 | 1] = cover[rt] ?0 : m >> 1;
        x[rt << 1] = x[rt << 1 | 1] = 0;
        cover[rt] = -1;
    }
    if(x[rt] != 0)
    {
        fxor(rt << 1);
        fxor(rt << 1 | 1);
        p[rt << 1] = (m - (m >> 1)) - p[rt << 1];
        p[rt << 1 | 1] = (m >> 1) - p[rt << 1 | 1];
        int k = lsum[rt << 1]; lsum[rt << 1] = lsun[rt << 1]; lsun[rt << 1] = k;
        k = rsum[rt << 1]; rsum[rt << 1] = rsun[rt << 1]; rsun[rt << 1] = k;
        k = msum[rt << 1]; msum[rt << 1] = msun[rt << 1]; msun[rt << 1] = k;
        k = lsum[rt << 1 | 1]; lsum[rt << 1 | 1] = lsun[rt << 1 | 1]; lsun[rt << 1 | 1] = k;
        k = rsum[rt << 1 | 1]; rsum[rt << 1 | 1] = rsun[rt << 1 | 1]; rsun[rt << 1 | 1] = k;
        k = msum[rt << 1 | 1]; msum[rt << 1 | 1] = msun[rt << 1 | 1]; msun[rt << 1 | 1] = k;
        x[rt] = 0;
    }
}

void build(int l, int r, int rt)
{
    if(l == r)
    {
        scanf("%d", &p[rt]);
        rsum[rt] = msum[rt] = lsum[rt] = p[rt] ? 1 : 0;
        rsun[rt] = msun[rt] = lsun[rt] = p[rt] ? 0 : 1;
        //printf("msum[rt] = %d\n", msum[rt]);
        return ;
    }
    mid ;
    build(lson);
    build(rson);
    PushUp(m, m+1, rt, r-l+1);
}

void update(int op, int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R)
    {
        if(op == 2)
        {
            p[rt] = r-l+1-p[rt];
            int k = lsum[rt]; lsum[rt] = lsun[rt]; lsun[rt] = k;
            k = rsum[rt]; rsum[rt] = rsun[rt]; rsun[rt] = k;
            k = msum[rt]; msum[rt] = msun[rt]; msun[rt] = k;
            fxor(rt);
        }
        else
        {
            cover[rt] = op;
            lsum[rt] = msum[rt] = rsum[rt] = p[rt] = op ? r-l+1 : 0;
            lsun[rt] = msun[rt] = rsun[rt] = op ? 0 : r-l+1;
            x[rt] = 0;
        }
        return ;
    }
    mid ;
    PushDown(rt, r-l+1);
    if(L <= m)
        update(op, L, R, lson);
    if(m < R)
        update(op, L, R, rson);
    PushUp(m, m+1, rt, r-l+1);
}

int query(int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R)
    {
        return p[rt];
    }
    int ret = 0;
    PushDown(rt, r-l+1);
    mid;
    if(L <= m)
        ret += query(L, R, lson);
    if(m < R)
        ret += query(L, R, rson);
    return ret ;
}

int Query(int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R)
    {
        return msum[rt];
    }
    mid;
    PushDown(rt, r-l+1);
    if(m < L)
        return Query(L, R, rson);
    else if(R <= m)
        return Query(L, R, lson);
    return max(max(min(rsum[rt << 1], m+1-L) + min(lsum[rt << 1 | 1], R-m), Query(L, R, lson)), Query(L, R, rson) );
}


int main()
{
    int T, n, m;
    scanf("%d", &T);
    while( T --)
    {
        memset(x, 0, sizeof(x));
        memset(cover, -1, sizeof(cover));
        scanf("%d%d", &n, &m);
        build(0, n-1, 1);

        while(m --)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            if(a < 3)
                update(a, b, c, 0, n-1, 1);
            else if(a == 3)
                printf("%d\n", query(b, c, 0, n-1, 1));
            else printf("%d\n", Query(b, c, 0, n-1, 1));
        }
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值