HDU 3397 Sequence operation (线段树)

思路:和POJ3225有点像,但是多了那么些操作。对于区间1的个数和翻转情况,这都是可以用懒惰标记解决的。对于连续1的个数,需要区间合并。具体还是看注释吧。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 100005
struct SegTree
{
    int l,r;
    int olm,orm,omm;//分别为从左开始出现最多的1,从又开始最多1,区间最多连续1
    int zlm,zrm,zmm;//同上,但是是0
    int sum;//区间1的个数
    bool flag;//翻转标记,当区间全部为0(sum==0)或者全部为1(sum==len())时,flag都是无意义的,标记为0,
    SegTree() {}
    int len()
    {
        return r-l+1;
    }
} tree[maxn<<2];
int array[maxn];
void pushUp(SegTree *rt,SegTree *ls,SegTree *rs)//区间合并
{
    rt->olm=ls->olm;
    if(ls->olm==ls->len()) rt->olm=ls->olm+rs->olm;
    rt->orm=rs->orm;
    if(rs->orm==rs->len()) rt->orm=rs->orm+ls->orm;
    rt->omm=max(rt->olm,rt->orm);
    rt->omm=max(rt->omm,max(ls->omm,rs->omm));
    rt->omm=max(rt->omm,ls->orm+rs->olm);

    rt->zlm=ls->zlm;
    if(ls->zlm==ls->len()) rt->zlm=ls->zlm+rs->zlm;
    rt->zrm=rs->zrm;
    if(rs->zrm==rs->len()) rt->zrm=rs->zrm+ls->zrm;
    rt->zmm=max(rt->zlm,rt->zrm);
    rt->zmm=max(rt->zmm,max(ls->zmm,rs->zmm));
    rt->zmm=max(rt->zmm,ls->zrm+rs->zlm);

    rt->sum=ls->sum+rs->sum;
}
inline void pushDown(int rt)//传递懒惰标记,更新左右孩子
{
    if(tree[rt].sum==tree[rt].len()||tree[rt].sum==0)
    {
        int ls=rt<<1,rs=rt<<1|1;
        tree[rt].flag=tree[ls].flag=tree[rs].flag=0;
        if(tree[rt].sum==0)
        {
            tree[ls].sum=tree[ls].olm=tree[ls].orm=tree[ls].omm=0;
            tree[rs].sum=tree[rs].olm=tree[rs].orm=tree[rs].omm=0;
            tree[ls].zlm=tree[ls].zrm=tree[ls].zmm=tree[ls].len();
            tree[rs].zlm=tree[rs].zrm=tree[rs].zmm=tree[rs].len();
        }
        else
        {
            tree[ls].sum=tree[ls].olm=tree[ls].orm=tree[ls].omm=tree[ls].len();
            tree[rs].sum=tree[rs].olm=tree[rs].orm=tree[rs].omm=tree[rs].len();
            tree[ls].zlm=tree[ls].zrm=tree[ls].zmm=0;
            tree[rs].zlm=tree[rs].zrm=tree[rs].zmm=0;
        }
    }
    if(tree[rt].flag)
    {
        int ls=rt<<1,rs=rt<<1|1;
        swap(tree[ls].olm,tree[ls].zlm);
        swap(tree[ls].orm,tree[ls].zrm);
        swap(tree[ls].omm,tree[ls].zmm);
        swap(tree[rs].olm,tree[rs].zlm);
        swap(tree[rs].orm,tree[rs].zrm);
        swap(tree[rs].omm,tree[rs].zmm);
        tree[rs].sum=tree[rs].len()-tree[rs].sum;
        tree[ls].sum=tree[ls].len()-tree[ls].sum;
        if(tree[ls].sum==tree[ls].len()||tree[ls].sum==0)
            tree[ls].flag=0;
        else tree[ls].flag^=1;
        if(tree[rs].sum==tree[rs].len()||tree[rs].sum==0)
            tree[rs].flag=0;
        else tree[rs].flag^=1;
        tree[rt].flag=0;
    }
}
void build(int rt,int l,int r)
{
    tree[rt].l=l,tree[rt].r=r;
    tree[rt].flag=0;
    if(l==r)
    {
        tree[rt].sum=tree[rt].olm=tree[rt].orm=tree[rt].omm=array[l];
        tree[rt].zlm=tree[rt].zrm=tree[rt].zmm=1-array[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pushUp(&tree[rt],&tree[rt<<1],&tree[rt<<1|1]);
}
void update(int rt,int l,int r,int op)
{
    if(tree[rt].l>=l&&tree[rt].r<=r)
    {
        if(op==0)
        {
            tree[rt].flag=0;
            tree[rt].sum=tree[rt].olm=tree[rt].orm=tree[rt].omm=0;
            tree[rt].zlm=tree[rt].zrm=tree[rt].zmm=tree[rt].len();
        }
        else if(op==1)
        {
            tree[rt].flag=0;
            tree[rt].sum=tree[rt].olm=tree[rt].orm=tree[rt].omm=tree[rt].len();
            tree[rt].zlm=tree[rt].zrm=tree[rt].zmm=0;
        }
        else if(op==2)
        {
            swap(tree[rt].olm,tree[rt].zlm);
            swap(tree[rt].orm,tree[rt].zrm);
            swap(tree[rt].omm,tree[rt].zmm);
            tree[rt].sum=tree[rt].len()-tree[rt].sum;
            if(tree[rt].sum==tree[rt].len()||tree[rt].sum==0)
                tree[rt].flag=0;
            else
                tree[rt].flag^=1;
        }
        return ;
    }
    if(tree[rt].l==tree[rt].r) return ;
    pushDown(rt);
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(l<=mid) update(rt<<1,l,r,op);
    if(r>mid) update(rt<<1|1,l,r,op);
    pushUp(&tree[rt],&tree[rt<<1],&tree[rt<<1|1]);
}
int Sum(int rt,int l,int r)//求区间1的个数
{
    if(tree[rt].l>=l&&tree[rt].r<=r)
        return tree[rt].sum;
    if(tree[rt].l==tree[rt].r) return tree[rt].sum;
    pushDown(rt);
    int mid=(tree[rt].l+tree[rt].r)>>1;
    int res=0;
    if(l<=mid) res+=Sum(rt<<1,l,r);
    if(r>mid) res+=Sum(rt<<1|1,l,r);
    pushUp(&tree[rt],&tree[rt<<1],&tree[rt<<1|1]);
    return res;
}
int LCS(int rt,int l,int r)//求区间最长连续1的个数
{
    if(tree[rt].l==l&&tree[rt].r==r)
        return tree[rt].omm;
    pushDown(rt);
    int mid=(tree[rt].l+tree[rt].r)>>1;
    int ans=0;
    if(r<=mid) ans=LCS(rt<<1,l,r);
    else if(l>mid) ans=LCS(rt<<1|1,l,r);
    else
    {
        int ls=LCS(rt<<1,l,mid);
        int rs=LCS(rt<<1|1,mid+1,r);
        ans=max(ls,rs);
        ans=max(ans,min(mid-l+1,tree[rt<<1].orm)+min(r-mid,tree[rt<<1|1].olm));
    }
    pushUp(&tree[rt],&tree[rt<<1],&tree[rt<<1|1]);
    return ans;
}
int main()
{
    int T;
    int n,m,op;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)
            scanf("%d",array+i);
        build(1,0,n-1);
//        printf("sum=%d\n",Sum(1,0,n-1));
//        printf("LCS=%d\n",LCS(1,0,n-1).omm);
        while(m--)
        {
            int a,b;
            scanf("%d%d%d",&op,&a,&b);
            if(op<3)
            {
                update(1,a,b,op);
//                printf("sum=%d\n",Sum(1,0,n-1));
//                printf("LCS=%d\n",LCS(1,0,n-1).omm);
            }
            else if(op==3)
            {
                printf("%d\n",Sum(1,a,b));
//                printf("sum=%d\n",Sum(1,0,n-1));
//                printf("LCS=%d\n",LCS(1,0,n-1).omm);
            }
            else
            {
                printf("%d\n",LCS(1,a,b));
//                printf("sum=%d\n",Sum(1,0,n-1));
//                printf("LCS=%d\n",LCS(1,0,n-1).omm);
            }
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值