hdu 3397 Sequence operation 线段树

题意:

给定长度为n的,由0,和1组成的序列,进行以下5种操作。

1)0 a b,将[a,b]区间内所有数变为0

2)1 a b,将[a,b]区间内所有数变为1

3)2 a b,将[a,b]区间内所以1变为0,所有0变为1.

4)3 a b,输出[a,b]区间内1的个数。

5)4 a b,输出[a,b]区间内连续1的最大长度。

题解:

建线段树,其中结点包括:

len:区间长度。

pre0:最长前缀连续0的长度。

aft0:最长后缀连续0的长度。

maxv0:最长连续0的长度。

pre1,aft1,maxv1与上同,表示连续1.

sum:表示区间内的所有数和,也就是区间内1的个数。

setv:懒惰标记,分4种,-1表示无,0表示变0操作,1表示变1操作,2表示异或操作。

问题主要在异或操作上,每次以后的时候,(pre0,aft0,maxv0)和(pre1,aft1,maxv1)交换即可(因为0都变成了1,1都变成了0)。

注意:这里的标记不是覆盖型的。。我就在这死的惨惨的。。每次遇到标记的时候要判断现有标记和新增标记,结合得到一个新的标记。




代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
using namespace std;

const int maxn=1e5+10;
struct node{
    int l,r,len;
    int pre0,aft0,maxv0;
    int pre1,aft1,maxv1;
    int sum;
    int setv;
}e[maxn*4];
int f[maxn];
void push_up(int c)
{
    if(e[2*c].pre0==e[2*c].len)e[c].pre0=e[2*c].pre0+e[2*c+1].pre0;
    else e[c].pre0=e[2*c].pre0;
    if(e[2*c+1].aft0==e[2*c+1].len)e[c].aft0=e[2*c+1].aft0+e[2*c].aft0;
    else e[c].aft0=e[2*c+1].aft0;
    e[c].maxv0=max(max(e[2*c].maxv0,e[2*c+1].maxv0),e[2*c].aft0+e[2*c+1].pre0);

    if(e[2*c].pre1==e[2*c].len)e[c].pre1=e[2*c].pre1+e[2*c+1].pre1;
    else e[c].pre1=e[2*c].pre1;
    if(e[2*c+1].aft1==e[2*c+1].len)e[c].aft1=e[2*c+1].aft1+e[2*c].aft1;
    else e[c].aft1=e[2*c+1].aft1;
    e[c].maxv1=max(max(e[2*c].maxv1,e[2*c+1].maxv1),e[2*c].aft1+e[2*c+1].pre1);

    e[c].sum=e[2*c].sum+e[2*c+1].sum;
}
void push_down(int c)
{
    if(e[c].setv!=-1)
    {
        if(e[c].setv==0)
        {
            e[2*c].pre0=e[2*c].aft0=e[2*c].maxv0=e[2*c].r-e[2*c].l+1;
            e[2*c].pre1=e[2*c].aft1=e[2*c].maxv1=e[2*c].sum=0;
            e[2*c+1].pre0=e[2*c+1].aft0=e[2*c+1].maxv0=e[2*c+1].r-e[2*c+1].l+1;
            e[2*c+1].pre1=e[2*c+1].aft1=e[2*c+1].maxv1=e[2*c+1].sum=0;
        }
        else if(e[c].setv==1)
        {
            e[2*c].pre0=e[2*c].aft0=e[2*c].maxv0=0;
            e[2*c].pre1=e[2*c].aft1=e[2*c].maxv1=e[2*c].sum=e[2*c].r-e[2*c].l+1;
            e[2*c+1].pre0=e[2*c+1].aft0=e[2*c+1].maxv0=0;
            e[2*c+1].pre1=e[2*c+1].aft1=e[2*c+1].maxv1=e[2*c+1].sum=e[2*c+1].r-e[2*c+1].l+1;
        }
        else
        {
            swap(e[2*c].pre0,e[2*c].pre1);
            swap(e[2*c].aft0,e[2*c].aft1);
            swap(e[2*c].maxv0,e[2*c].maxv1);
            e[2*c].sum=e[2*c].r-e[2*c].l+1-e[2*c].sum;
            swap(e[2*c+1].pre0,e[2*c+1].pre1);
            swap(e[2*c+1].aft0,e[2*c+1].aft1);
            swap(e[2*c+1].maxv0,e[2*c+1].maxv1);
            e[2*c+1].sum=e[2*c+1].r-e[2*c+1].l+1-e[2*c+1].sum;
        }
        if(e[c].setv<2)e[2*c].setv=e[2*c+1].setv=e[c].setv;
        else
        {
            if(e[2*c].setv==-1)e[2*c].setv=2;
            else if(e[2*c].setv==0)e[2*c].setv=1;
            else if(e[2*c].setv==1)e[2*c].setv=0;
            else e[2*c].setv=-1;

            if(e[2*c+1].setv==-1)e[2*c+1].setv=2;
            else if(e[2*c+1].setv==0)e[2*c+1].setv=1;
            else if(e[2*c+1].setv==1)e[2*c+1].setv=0;
            else e[2*c+1].setv=-1;
        }
        e[c].setv=-1;
    }
}
void build(int a,int b,int c)
{
    if(a==b)
    {
        e[c].l=e[c].r=a;
        e[c].len=1;
        e[c].pre0=e[c].aft0=e[c].maxv0=(f[a]==1?0:1);
        e[c].pre1=e[c].aft1=e[c].maxv1=(f[a]==1?1:0);
        e[c].setv=-1;
        e[c].sum=f[a];
        return ;
    }
    int mid=(a+b)/2;
    build(a,mid,2*c);
    build(mid+1,b,2*c+1);
    e[c].l=a;e[c].r=b;e[c].len=b-a+1;
    push_up(c);
    e[c].setv=-1;
}
void update(int a,int b,int c,int val)
{
   // printf("%d %d\n",e[c].l,e[c].r);
    if(e[c].l==a&&e[c].r==b)
    {
        if(val==0)
        {
            e[c].pre0=e[c].aft0=e[c].maxv0=b-a+1;
            e[c].pre1=e[c].aft1=e[c].maxv1=0;
            e[c].sum=0;
        }
        else if(val==1)
        {
            e[c].pre0=e[c].aft0=e[c].maxv0=0;
            e[c].pre1=e[c].aft1=e[c].maxv1=b-a+1;
            e[c].sum=b-a+1;
        }
        else if(val==2)
        {
            swap(e[c].pre0,e[c].pre1);
            swap(e[c].aft0,e[c].aft1);
            swap(e[c].maxv0,e[c].maxv1);
            e[c].sum=b-a+1-e[c].sum;
        }
        if(val==0||val==1)e[c].setv=val;
        else
        {
            if(e[c].setv==-1)e[c].setv=2;
            else if(e[c].setv==0)e[c].setv=1;
            else if(e[c].setv==1)e[c].setv=0;
            else e[c].setv=-1;
        }
        //printf("**%d %d %d\n",e[c].l,e[c].r,e[c].sum);
        return ;
    }
    push_down(c);
    int mid=(e[c].l+e[c].r)/2;
    if(b<=mid)update(a,b,2*c,val);
    else if(a>mid)update(a,b,2*c+1,val);
    else
    {
        update(a,mid,2*c,val);
        update(mid+1,b,2*c+1,val);
    }
    push_up(c);
    //printf("*%d %d %d\n",e[c].l,e[c].r,e[c].sum);
}
node query(int a,int b,int c)
{
    if(e[c].l==a&&e[c].r==b)
    {
        return e[c];
    }
    push_down(c);
    int mid=(e[c].l+e[c].r)/2;
    if(b<=mid)return query(a,b,2*c);
    else if(a>mid)return query(a,b,2*c+1);
    else
    {
        node o,p,q;
        p=query(a,mid,2*c);q=query(mid+1,b,2*c+1);
        if(p.pre1==p.len)o.pre1=p.pre1+q.pre1;
        else o.pre1=p.pre1;
        if(q.aft1==q.len)o.aft1=q.aft1+p.aft1;
        else o.aft1=q.aft1;
        o.maxv1=max(max(p.maxv1,q.maxv1),p.aft1+q.pre1);
        o.sum=p.sum+q.sum;
        o.len=p.len+q.len;
        return o;
    }
}
int main()
{
    //freopen("D:\\in.txt","r",stdin);
    //freopen("D:\\out.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int i,j,k,n,m,a,b,c;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)scanf("%d",&f[i]);
        build(1,n,1);
        node ans;
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            b++;c++;
            if(a<3)update(b,c,1,a);
            else
            {
                ans=query(b,c,1);
                if(a==3)printf("%d\n",ans.sum);
                else printf("%d\n",ans.maxv1);
            }
        }
    }
    return 0;
}
/*
1
10 10
0 0 1 1 1 0 0 0 0 0
2 1 6
2 2 6
2 1 3
4 1 6

1

1
10 10
0 0 0 0 0 0 0 1 0 1
2 4 7
1 1 6
2 0 5
2 4 6
3 2 4
3 1 5
3 2 2

1
2
0


*/


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值