1026 - 线段树 - 序列操作[SCOI2010]

传送门

分析

不错,蛮好的一道题
对于操作0,1,我们维护区间覆盖的标记 t a g [ i ] tag[i] tag[i]
操作2,我们维护区间取反标记 r e v [ i ] rev[i] rev[i]
在区间覆盖的时候,取反标记置为-1
在区间取反的时候,直接修改 r e v rev rev
操作三就是维护一下区间和即可 s u m [ i ] sum[i] sum[i]
操作四维护6个值:
从左数最多有多少个连续的1
从右数最多有多少个连续的1
整个区间最多有多少个连续的1
同理,对于0,我们还有3个值要维护
其实还是蛮好写的
就是数组的实现方式会很复杂且麻烦,至少我还没有转出来
如果有过路大佬会使用数组实现,分享一下呗
最后在gsj大佬和ldx大佬的建议下,我还是改用了结构体来做,确实很方便啊!!
我打算改板子了……嗯,就用结构体吧,思路清晰,代码简短易懂

代码
#include<bits/stdc++.h>
#define in read()
#define N 100009
#define lc (k<<1)
#define rc (k<<1)|1
using namespace std;
inline int read(){
    char ch;int f=1,res=0;
    while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    while(ch>='0'&&ch<='9'){
        res=(res<<3)+(res<<1)+ch-'0';
        ch=getchar();
    }
    return f==1?res:-res;
}
int n,m,A[N];
struct node{
    int sum,l[2],r[2],maxn[2];
    int rev,tag,len;
    friend inline node operator+(const node &a,const node &b){
        node res;
        res.tag=-1;res.rev=0;//这个地方一定不能忘了赋值,因为这次是把res返回
        res.sum=a.sum+b.sum;res.len=a.len+b.len;
        for(int i=0;i<=1;++i){
            res.l[i]=(a.l[i]==a.len)?a.l[i]+b.l[i]:a.l[i];
            res.r[i]=(b.r[i]==b.len)?b.r[i]+a.r[i]:b.r[i];
            res.maxn[i]=max(max(a.maxn[i],b.maxn[i]),a.r[i]+b.l[i]);
        }
        return res;
    }
}seg[N<<2];
inline void C(int k,int l,int r,int v){
    seg[k].rev=0;seg[k].tag=v;
    seg[k].sum=(r-l+1)*v;
    seg[k].l[1]=seg[k].r[1]=seg[k].maxn[1]=v*(r-l+1);
    seg[k].l[0]=seg[k].r[0]=seg[k].maxn[0]=(v^1)*(r-l+1);
}
inline void R(int k,int l,int r){
    seg[k].rev^=1;seg[k].sum=(r-l+1)-seg[k].sum;
    swap(seg[k].l[1],seg[k].l[0]);swap(seg[k].r[1],seg[k].r[0]);
    swap(seg[k].maxn[0],seg[k].maxn[1]);
}
inline void pushdown(int k,int l,int r){
    int mid=l+r>>1;
    if(seg[k].tag!=-1) C(lc,l,mid,seg[k].tag),C(rc,mid+1,r,seg[k].tag),seg[k].tag=-1;
    if(seg[k].rev) R(lc,l,mid),R(rc,mid+1,r),seg[k].rev=0;
}
inline void build(int k,int l,int r){
    seg[k].tag=-1;seg[k].rev=0;
    if(l==r){
        seg[k].sum=A[l];seg[k].len=1;
        seg[k].l[1]=seg[k].r[1]=seg[k].maxn[1]=A[l]*(r-l+1);
        seg[k].l[0]=seg[k].r[0]=seg[k].maxn[0]=(A[l]^1)*(r-l+1);
        return;
    }
    int mid=l+r>>1;
    build(lc,l,mid);build(rc,mid+1,r);
    seg[k]=seg[lc]+seg[rc];
}
inline void cover(int k,int l,int r,int x,int y,int v){
    if(x<=l&&r<=y){	C(k,l,r,v);	return;}
    pushdown(k,l,r);
    int mid=l+r>>1;
    if(x<=mid) cover(lc,l,mid,x,y,v);
    if(y>mid) cover(rc,mid+1,r,x,y,v);
    seg[k]=seg[lc]+seg[rc];
}
inline void reverse(int k,int l,int r,int x,int y){
    if(x<=l&&r<=y){R(k,l,r);return;}
    pushdown(k,l,r);
    int mid=l+r>>1;
    if(x<=mid) reverse(lc,l,mid,x,y);
    if(y>mid) reverse(rc,mid+1,r,x,y);
    seg[k]=seg[lc]+seg[rc];
}
inline node query(int k,int l,int r,int x,int y){
    if(x<=l&&r<=y){return seg[k];}
    pushdown(k,l,r);
    int mid=l+r>>1;
    if(y<=mid) return query(lc,l,mid,x,y);
    if(x>mid) return query(rc,mid+1,r,x,y);
    return query(lc,l,mid,x,y)+query(rc,mid+1,r,x,y);
}
int main(){
    n=in;m=in;
    int i,j,k;
    for(i=1;i<=n;++i) A[i]=in;
    build(1,1,n);
    int op,a,b;
    for(i=1;i<=m;++i){
        op=in;a=in;b=in;a++;b++;
        if(op==0) {	cover(1,1,n,a,b,0);	}
        if(op==1) {	cover(1,1,n,a,b,1);	}
        if(op==2) {	reverse(1,1,n,a,b);	}//
        if(op==3) {	printf("%d\n",query(1,1,n,a,b).sum);}
        if(op==4) {	printf("%d\n",query(1,1,n,a,b).maxn[1]);}
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值