HDU 3397 Sequence operation

【题意】操作区间上只有0和1,操作有两个,第一个是区间染色,第二个是区间反转(01变换).询问也用两个,一个是询问区间内1个个数,二是询问区间内最长的连续的1的个数。

【解题方法】典型的线段树区间合并。难点是有2种区间操作,处理好这两种操作的关系,这道题也就没有难点了。我们观察可以发现,覆盖的优先级高于反转。无论这个区间怎样反转,只要来一次覆盖,所有的反转都将会失效。所以,在pushdown的时候,如果有染色的话,我们直接把作友儿子的反转标记置0。而且在一个节点上,反转和覆盖不会同时存在,即使某个区间刚被覆盖,我们对他进行反转的时候,我们直接反转覆盖值即可。这里,标记反转有个技巧,反转2次就是没反转,我们用异或1来代表一次反转操作。

【AC 代码】

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=100010;
struct node{
    int l,r,len;
    int l0,r0,s0;
    int l1,r1,s1;
    int sum;//区间1的个数
    int mark;//区间反转标记
    int cover;//区间覆盖标记
}Tree[maxn<<2];

void pushup(int rt)
{
    Tree[rt].l1=Tree[rt*2].l1;
    Tree[rt].r1=Tree[rt*2+1].r1;
    if(Tree[rt].l1==Tree[rt*2].len) Tree[rt].l1=Tree[rt*2].l1+Tree[rt*2+1].l1;
    if(Tree[rt].r1==Tree[rt*2+1].len) Tree[rt].r1=Tree[rt*2].r1+Tree[rt*2+1].len;
    Tree[rt].s1=max(max(Tree[rt*2].s1,Tree[rt*2+1].s1),Tree[rt*2].r1+Tree[rt*2+1].l1);

    Tree[rt].l0=Tree[rt*2].l0;
    Tree[rt].r0=Tree[rt*2+1].r0;
    if(Tree[rt].l0==Tree[rt*2].len) Tree[rt].l0=Tree[rt*2].len+Tree[rt*2+1].l0;
    if(Tree[rt].r0==Tree[rt*2+1].len) Tree[rt].r0=Tree[rt*2].r0+Tree[rt*2+1].len;
    Tree[rt].s0=max(max(Tree[rt*2].s0,Tree[rt*2+1].s0),Tree[rt*2].r0+Tree[rt*2+1].l0);

    Tree[rt].sum=Tree[rt*2].sum+Tree[rt*2+1].sum;
}
void change(int rt,int v)//对节点的信息进行修改
{
    if(v==0||v==1){//覆盖处理
        Tree[rt].l1=Tree[rt].r1=Tree[rt].s1=v?Tree[rt].len:0;
        Tree[rt].l0=Tree[rt].r0=Tree[rt].s0=v?0:Tree[rt].len;
        Tree[rt].sum=v?Tree[rt].len:0;
        Tree[rt].cover=v;
    }
    else{//XOR
        swap(Tree[rt].l0,Tree[rt].l1);
        swap(Tree[rt].r0,Tree[rt].r1);
        swap(Tree[rt].s0,Tree[rt].s1);
        Tree[rt].sum=Tree[rt].len-Tree[rt].sum;
        Tree[rt].mark^=1;
        if(Tree[rt].cover!=-1){
            Tree[rt].cover=1-Tree[rt].cover;
        }
    }
}
void pushdown(int rt)
{
    if(Tree[rt].mark){
        change(rt*2,2);
        change(rt*2+1,2);
        Tree[rt].mark=0;
    }
    if(Tree[rt].cover!=-1){
        change(rt*2,Tree[rt].cover);
        change(rt*2+1,Tree[rt].cover);
        Tree[rt].cover=-1;
    }
}
void Build(int l,int r,int rt)
{
    Tree[rt].l=l,Tree[rt].r=r,Tree[rt].len=r-l+1;
    Tree[rt].mark=0,Tree[rt].cover=-1;
    if(l==r){
        int x;
        scanf("%d",&x);
        Tree[rt].l0=Tree[rt].r0=Tree[rt].s0=x?0:1;
        Tree[rt].l1=Tree[rt].r1=Tree[rt].s1=x?1:0;
        Tree[rt].sum=x?1:0;
        return ;
    }
    int mid=(l+r)/2;
    Build(l,mid,rt*2);
    Build(mid+1,r,rt*2+1);
    pushup(rt);
}

void update(int L,int R,int kind,int rt)
{
    if(L==Tree[rt].l&&Tree[rt].r==R){
        change(rt,kind);
        return ;
    }
    pushdown(rt);
    int mid=(Tree[rt].l+Tree[rt].r)/2;
    if(R<=mid) update(L,R,kind,rt*2);
    else if(L>mid) update(L,R,kind,rt*2+1);
    else{
        update(L,mid,kind,rt*2);
        update(mid+1,R,kind,rt*2+1);
    }
    pushup(rt);
}
int queryans(int L,int R,int kind,int rt)
{
    if(L==Tree[rt].l&&Tree[rt].r==R){
        if(kind==3) return Tree[rt].sum;
        else return Tree[rt].s1;
    }
    pushdown(rt);
    int mid=(Tree[rt].l+Tree[rt].r)/2;
    if(R<=mid) return queryans(L,R,kind,rt*2);
    else if(L>mid) return queryans(L,R,kind,rt*2+1);
    else{
        int ans1,ans2;
        ans1=queryans(L,mid,kind,rt*2);
        ans2=queryans(mid+1,R,kind,rt*2+1);
        if(kind==3) return ans1+ans2;
        else return max(max(ans1,ans2),min(mid-L+1,Tree[rt*2].r1)+min(R-mid,Tree[rt*2+1].l1));
    }
}
int main()
{
    int T,n,q;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&q);
        Build(1,n,1);
        //puts("success");
        int op,l,r;
        while(q--){
            scanf("%d%d%d",&op,&l,&r);
            l++,r++;
            if(op<=2) update(l,r,op,1);
            else if(op>=3){
                printf("%d\n",queryans(l,r,op,1));
            }
        }
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值