bzoj1858 [Scoi2010]序列操作

传送门

线段树+细节。
主要思路都是正确的,但是细节,,细节,,
区间覆盖要把翻转标记清空!!!

CODE:

#include<cstdio>
#define N 100005
struct tree
{
    int num,num0,num1,left0,left1,right0,right1,max0,max1;
    bool set0,set1,swap;
    inline void swp(int &a,int &b){a^=b,b^=a,a^=b;}
    inline void set(int wh,int cnt)
    {
        num=wh;
        num0=left0=right0=max0=!wh?cnt:0;
        num1=left1=right1=max1=wh?cnt:0;
        set0=!wh?1:0,set1=wh?1:0;
        swap=0;
    }
    inline void Swap()
    {
        num^=1;
        swp(num0,num1);
        swp(left0,left1);
        swp(right0,right1);
        swp(max0,max1);
        swap^=1;
    }
}t[N<<2];
int n,m,opt,x,y;
inline int max(const int &a,const int &b){return a>b?a:b;}
inline int min(const int &a,const int &b){return a<b?a:b;}
inline void pushdown(int l,int r,int now)
{
    if(!t[now].set0&&!t[now].set1&&!t[now].swap) return;
    int mid=(l+r)>>1,s1=now<<1,s2=now<<1|1;
    if(t[now].set0) t[s1].set(0,mid-l+1),t[s2].set(0,r-mid),t[now].set0=0;
    if(t[now].set1) t[s1].set(1,mid-l+1),t[s2].set(1,r-mid),t[now].set1=0;
    if(t[now].swap) t[s1].Swap(),t[s2].Swap(),t[now].swap=0;
}
inline void update(int l,int r,int now)
{
    int mid=(l+r)>>1,s1=now<<1,s2=now<<1|1;
    t[now].left0=t[s1].left0;
    if(t[s1].left0==mid-l+1) t[now].left0+=t[s2].left0;
    t[now].left1=t[s1].left1;
    if(t[s1].left1==mid-l+1) t[now].left1+=t[s2].left1;
    t[now].num0=t[s1].num0+t[s2].num0;
    t[now].num1=t[s1].num1+t[s2].num1;
    t[now].right0=t[s2].right0;
    if(t[s2].right0==r-mid) t[now].right0+=t[s1].right0;
    t[now].right1=t[s2].right1;
    if(t[s2].right1==r-mid) t[now].right1+=t[s1].right1;
    t[now].max0=max(t[s1].right0+t[s2].left0,max(max(t[s1].max0,t[s2].max0),max(t[now].left0,t[now].right0)));
    t[now].max1=max(t[s1].right1+t[s2].left1,max(max(t[s1].max1,t[s2].max1),max(t[now].left1,t[now].right1)));
}
void build(int l,int r,int now)
{
    if(l==r)
    {
        int tmp;
        scanf("%d",&tmp);
        t[now].set(tmp,1);
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,now<<1);
    build(mid+1,r,now<<1|1);
    update(l,r,now);
}
void change(int L,int R,int l,int r,int now,int num)
{
    if(L<=l&&r<=R) return t[now].set(num,r-l+1);
    int mid=(l+r)>>1;
    pushdown(l,r,now);
    if(L<=mid) change(L,R,l,mid,now<<1,num);
    if(R>mid) change(L,R,mid+1,r,now<<1|1,num);
    update(l,r,now);
}
void swap(int L,int R,int l,int r,int now)
{
    if(L<=l&&r<=R) return t[now].Swap();
    int mid=(l+r)>>1;
    pushdown(l,r,now);
    if(L<=mid) swap(L,R,l,mid,now<<1);
    if(R>mid) swap(L,R,mid+1,r,now<<1|1);
    update(l,r,now);
}
int ask(int L,int R,int l,int r,int now)
{
    if(L<=l&&r<=R) return t[now].num1;
    int mid=(l+r)>>1,ans=0;
    pushdown(l,r,now);
    if(L<=mid) ans=ask(L,R,l,mid,now<<1);
    if(R>mid) ans+=ask(L,R,mid+1,r,now<<1|1);
    return ans;
}
tree askmax(int L,int R,int l,int r,int now)
{
    if(L<=l&&r<=R) return t[now];
    int mid=(l+r)>>1;
    pushdown(l,r,now);
    if(R<=mid) return askmax(L,R,l,mid,now<<1);
    if(L>mid) return askmax(L,R,mid+1,r,now<<1|1);
    tree tmp1,tmp2,ans;
    tmp1=askmax(L,R,l,mid,now<<1);
    tmp2=askmax(L,R,mid+1,r,now<<1|1);
    ans.left1=tmp1.left1;
    if(tmp1.left1==mid-max(L,l)+1) ans.left1+=tmp2.left1;
    ans.right1=tmp2.right1;
    if(tmp2.right1==min(r,R)-mid) ans.right1+=tmp1.right1;
    ans.max1=max(tmp1.right1+tmp2.left1,max(max(tmp1.max1,tmp2.max1),max(ans.left1,ans.right1)));
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    build(1,n,1);
    while(m--)
    {
        scanf("%d%d%d",&opt,&x,&y),x++,y++;
        if(!opt) change(x,y,1,n,1,0);
        else if(opt==1) change(x,y,1,n,1,1);
        else if(opt==2) swap(x,y,1,n,1);
        else if(opt==3) printf("%d\n",ask(x,y,1,n,1));
        else printf("%d\n",askmax(x,y,1,n,1).max1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值