Sequence operation HDU - 3397

点击打开链接

写了好久 终于AC 还是对线段树理解不到位

0 1操作是裸区间着色 2操作是裸区间翻转(异或) 对于这两种区间操作各设两个laz变量

3操作是裸区间查询 4操作略有技巧 可以先做一下hdu3911 来弄明白4操作

这题关键是处理好着色与翻转的先后顺序关系 举个例子:

设区间 [0,4] 为 1 1 0 1 1 有两个操作 a: 0 0 4 和 b: 2 0 4

先a后b得 1 1 1 1 1 先b后a得 0 0 0 0 0 结果截然相反

 

思路 如果某一个区间上只有一种标记 正常pushdown即可 但如果两者都有 必须保证着色优先级更高

1 若先有着色后有翻转 则执行完着色 再执行翻转

2 若先有翻转后有着色 则放弃执行翻转 直接执行着色

但是怎么实现呢? 难道开个变量记录先后次序? 如下:

在给某区间打着色标记后移除翻转标记 打翻转标记则不用管着色标记 这样就体现了先后顺序

pushdown时也是一样操作 先看该区间有没有着色标记 有的话向下打给子区间 同时移除子区间的翻转标记

如果该区间还有翻转标记 向下打给子区间即可

 

#include <bits/stdc++.h>
using namespace std;

struct node
{
    int l;
    int r;

    int val;
    int left0;
    int right0;
    int all0;
    int left1;
    int right1;
    int all1;

    int laz1;
    int laz2;
};

node tree[400010];
int n;

void changeI(int cur,int val)
{
    if(val)
    {
        tree[cur].val=tree[cur].r-tree[cur].l+1;
        tree[cur].left0=tree[cur].right0=tree[cur].all0=0;
        tree[cur].left1=tree[cur].right1=tree[cur].all1=tree[cur].r-tree[cur].l+1;
    }
    else
    {
        tree[cur].val=0;
        tree[cur].left0=tree[cur].right0=tree[cur].all0=tree[cur].r-tree[cur].l+1;
        tree[cur].left1=tree[cur].right1=tree[cur].all1=0;
    }
    return;
}

void changeII(int cur)
{
    swap(tree[cur].left0,tree[cur].left1);
    swap(tree[cur].right0,tree[cur].right1);
    swap(tree[cur].all0,tree[cur].all1);
    tree[cur].val=(tree[cur].r-tree[cur].l+1)-tree[cur].val;
    return;
}

void pushup(int cur)
{
    tree[cur].val=tree[2*cur].val+tree[2*cur+1].val;

    tree[cur].left0=tree[2*cur].left0;
    if(tree[cur].left0==tree[2*cur].r-tree[2*cur].l+1) tree[cur].left0+=tree[2*cur+1].left0;
    tree[cur].right0=tree[2*cur+1].right0;
    if(tree[cur].right0==tree[2*cur+1].r-tree[2*cur+1].l+1) tree[cur].right0+=tree[2*cur].right0;
    tree[cur].all0=max(tree[2*cur].right0+tree[2*cur+1].left0,max(tree[2*cur].all0,tree[2*cur+1].all0));

    tree[cur].left1=tree[2*cur].left1;
    if(tree[cur].left1==tree[2*cur].r-tree[2*cur].l+1) tree[cur].left1+=tree[2*cur+1].left1;
    tree[cur].right1=tree[2*cur+1].right1;
    if(tree[cur].right1==tree[2*cur+1].r-tree[2*cur+1].l+1) tree[cur].right1+=tree[2*cur].right1;
    tree[cur].all1=max(tree[2*cur].right1+tree[2*cur+1].left1,max(tree[2*cur].all1,tree[2*cur+1].all1));
    return;
}

void pushdown(int cur)
{
    if(tree[cur].laz1!=-1)
    {
        changeI(2*cur,tree[cur].laz1);
        tree[2*cur].laz1=tree[cur].laz1;
        tree[2*cur].laz2=0;
        changeI(2*cur+1,tree[cur].laz1);
        tree[2*cur+1].laz1=tree[cur].laz1;
        tree[2*cur+1].laz2=0;
        tree[cur].laz1=-1;
    }
    if(tree[cur].laz2!=0)
    {
        changeII(2*cur);
        tree[2*cur].laz2^=1;
        changeII(2*cur+1);
        tree[2*cur+1].laz2^=1;
        tree[cur].laz2=0;
    }
    return;
}

void build(int l,int r,int cur)
{
    int m,t;
    tree[cur].l=l;
    tree[cur].r=r;
    tree[cur].laz1=-1;
    tree[cur].laz2=0;
    if(l==r)
    {
        scanf("%d",&t);
        if(t)
        {
            tree[cur].val=1;
            tree[cur].left0=tree[cur].right0=tree[cur].all0=0;
            tree[cur].left1=tree[cur].right1=tree[cur].all1=1;
        }
        else
        {
            tree[cur].val=0;
            tree[cur].left0=tree[cur].right0=tree[cur].all0=1;
            tree[cur].left1=tree[cur].right1=tree[cur].all1=0;
        }
        return;
    }
    m=(l+r)/2;
    build(l,m,2*cur);
    build(m+1,r,2*cur+1);
    pushup(cur);
    return;
}

void updateI(int pl,int pr,int val,int cur)
{
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        changeI(cur,val);
        tree[cur].laz1=val;
        tree[cur].laz2=0;
        return;
    }
    pushdown(cur);
    if(pl<=tree[2*cur].r) updateI(pl,pr,val,2*cur);
    if(pr>=tree[2*cur+1].l) updateI(pl,pr,val,2*cur+1);
    pushup(cur);
    return;
}

void updateII(int pl,int pr,int cur)
{
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        changeII(cur);
        tree[cur].laz2^=1;
        return;
    }
    pushdown(cur);
    if(pl<=tree[2*cur].r) updateII(pl,pr,2*cur);
    if(pr>=tree[2*cur+1].l) updateII(pl,pr,2*cur+1);
    pushup(cur);
    return;
}

int queryI(int pl,int pr,int cur)
{
    int res;
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        return tree[cur].val;
    }
    pushdown(cur);
    res=0;
    if(pl<=tree[2*cur].r) res+=queryI(pl,pr,2*cur);
    if(pr>=tree[2*cur+1].l) res+=queryI(pl,pr,2*cur+1);
    return res;
}

int queryII(int pl,int pr,int cur)
{
    int tl,tr,tm;
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        return tree[cur].all1;
    }
    pushdown(cur);
    if(pr<=tree[2*cur].r) return queryII(pl,pr,2*cur);
    else if(pl>=tree[2*cur+1].l) return queryII(pl,pr,2*cur+1);
    else
    {
        tl=queryII(pl,pr,2*cur),tr=queryII(pl,pr,2*cur+1);
        tm=min(tree[2*cur].r-pl+1,tree[2*cur].right1)+min(pr-tree[2*cur+1].l+1,tree[2*cur+1].left1);
        return max(tm,max(tl,tr));
    }
}

int main()
{
    int t,q,op,l,r;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&q);
        build(0,n-1,1);
        while(q--)
        {
            scanf("%d%d%d",&op,&l,&r);
            if(op==0)
            {
                updateI(l,r,0,1);
            }
            else if(op==1)
            {
                updateI(l,r,1,1);
            }
            else if(op==2)
            {
                updateII(l,r,1);
            }
            else if(op==3)
            {
                printf("%d\n",queryI(l,r,1));
            }
            else
            {
                printf("%d\n",queryII(l,r,1));
            }
        }
    }
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值