HDU-3397-Sequence operation(区间染色 连续为1的序列)

题目
lxhgww得到一个包含n个字符的序列,这些字符都是“0”或“1”。
我们有五个操作:
改变操作:
将[a, b]中的所有字符改为’0’
将[a, b]中的所有字符改为’1’
把所有的0都变成1把所有的1都变成0
输出操作:
输出[a, b]中’1’的个数
输出[a, b]中最长的连续“1”字符串的长度。

输入

第一行中的T(T<=10)是箱号。
每一种情况在第一行有两个整数:n和m (1 <= n, m <= 100000)。
下一行包含n个字符,“0”或“1”由空格分隔。
m行为操作:
op a b: 0 <= op <= 4, 0 <= a <= b < n。

输出

对于每个输出操作,输出结果。

用 ls[ ] ,rs[ ] 前后缀连续为1的数列长度。
fs[pos]=max( fs[pos<<1],fs[pos<<1|1]).
fs[pos]=max( fs[pos], min(mid-cl+1,rs[pos<<1])+min(cr-mid,ls[pos<<1|1]).

区间染色

其中 异或 的时候相当于对 tag[pos]!=-1的左右区间 分别染色。故此时需要判断tag[pos]!=-1? 。。若等于-1的话。区间还要继续往下划分。因此tag 一定要上推。为什么要有pushdown呢。因为很好理解吧。

#include<bits/stdc++.h>
using namespace std;
const int N=100005<<2;
int sum[N],tag[N],fs[N],ls[N],rs[N],cur[N];
void pushup(int ln,int rn,int pos){
    (tag[pos<<1]==tag[pos<<1|1])?tag[pos]=tag[pos<<1]:tag[pos]=-1;
    if(tag[pos]!=-1) sum[pos]=fs[pos]=ls[pos]=rs[pos]=(tag[pos]?(ln+rn):0);
    else{
        sum[pos]=sum[pos<<1]+sum[pos<<1|1];
        fs[pos]=max(fs[pos<<1],fs[pos<<1|1]);
        fs[pos]=max(fs[pos],rs[pos<<1]+ls[pos<<1|1]);
        ls[pos]=ls[pos<<1],rs[pos]=rs[pos<<1|1];
        if(ls[pos<<1]==ln) ls[pos]=ln+ls[pos<<1|1];
        if(rs[pos<<1|1]==rn) rs[pos]=rs[pos<<1]+rn;
    }
}
void build(int l,int r,int pos){
    if(l==r){
        tag[pos]=cur[l],sum[pos]=fs[pos]=ls[pos]=rs[pos]=cur[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,pos<<1),build(mid+1,r,pos<<1|1);
    pushup(mid-l+1,r-mid,pos);
}
void pushdown(int ln,int rn,int pos){
    if(tag[pos]==-1) return;
    tag[pos<<1]=tag[pos<<1|1]=tag[pos];
    sum[pos<<1]=fs[pos<<1]=ls[pos<<1]=rs[pos<<1]=(tag[pos]?ln:0);
    sum[pos<<1|1]=fs[pos<<1|1]=ls[pos<<1|1]=rs[pos<<1|1]=(tag[pos]?rn:0);
    //tag[pos]=-1;    //将此处的标记取消。要不要都可以 因为有tag上推
}
void chanspan(int cl,int cr,int val,int l,int r,int pos){
    if(cl<=l&&r<=cr){
        tag[pos]=val,sum[pos]=fs[pos]=ls[pos]=rs[pos]=(tag[pos]?(r-l+1):0);
        return;
    }
    int mid=(l+r)>>1;
    pushdown(mid-l+1,r-mid,pos);
    if(cl<=mid) chanspan(cl,cr,val,l,mid,pos<<1);
    if(cr>mid) chanspan(cl,cr,val,mid+1,r,pos<<1|1);
    pushup(mid-l+1,r-mid,pos);
}
void chanxor(int cl,int cr,int l,int r,int pos){   //区间异或
    if(cl<=l&&r<=cr&&tag[pos]!=-1){//这种做法必须找到左右区间染色相同的才可.故tag上推很必要
        tag[pos]^=1,sum[pos]=fs[pos]=ls[pos]=rs[pos]=(tag[pos]?(r-l+1):0);
        return;
    }
    int mid=(l+r)>>1;
    pushdown(mid-l+1,r-mid,pos);
    if(cl<=mid) chanxor(cl,cr,l,mid,pos<<1);
    if(cr>mid) chanxor(cl,cr,mid+1,r,pos<<1|1);
    pushup(mid-l+1,r-mid,pos);
}
int series_1(int cl,int cr,int l,int r,int pos){
    if(cl<=l&&r<=cr) return fs[pos];
    int mid=(l+r)>>1;
    pushdown(mid-l+1,r-mid,pos);
    int ans=-1;
    if(cl<=mid) ans=max(ans,series_1(cl,cr,l,mid,pos<<1));
    if(cr>mid) ans=max(ans,series_1(cl,cr,mid+1,r,pos<<1|1));
    ans=max(ans,min(mid-cl+1,rs[pos<<1])+min(cr-mid,ls[pos<<1|1]));//注意!!!需要比较一下.自己想想就知道为什么了
    return ans;
}
int num_1(int cl,int cr,int l,int r,int pos){
    if(cl<=l&&r<=cr) return sum[pos];
    int mid=(l+r)>>1;
    pushdown(mid-l+1,r-mid,pos);
    int ans=0;
    if(cl<=mid) ans+=num_1(cl,cr,l,mid,pos<<1);
    if(cr>mid) ans+=num_1(cl,cr,mid+1,r,pos<<1|1);
    return ans;
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        int n,m;scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&cur[i]);
        build(1,n,1);
        while(m--){
            int k,cl,cr;scanf("%d%d%d",&k,&cl,&cr),++cl,++cr;
            if(k==0) chanspan(cl,cr,0,1,n,1);
            if(k==1) chanspan(cl,cr,1,1,n,1);
            if(k==2) chanxor(cl,cr,1,n,1);
            if(k==3) printf("%d\n",num_1(cl,cr,1,n,1));
            if(k==4) printf("%d\n",series_1(cl,cr,1,n,1));
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值