把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ1858】[SCOI2010] 序列操作(ODT裸题)

点此看题面

大致题意: 给你一个\(01\)序列,让你支持区间赋值、区间取反、区间求和以及求一段区间内最多有多少连续的\(1\)这些操作。

\(ODT\)

这道题正解似乎是线段树,但码量较大,而且细节也很多。

而用\(ODT\)来做这道题就非常简单了。

区间赋值

就相当于\(ODT\)\(Assign\)操作。

区间取反

暴力扫一遍,将每个点的值异或\(1\)即可。

区间求和

暴力扫一遍,统计每个点的长度乘以权值的和即可。

求一段区间内最多有多少连续的\(1\)

暴力扫一遍,统计有多少个连续的\(1\),然后更新\(res\)\(max\)即可。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define Gmax(x,y) (x<(y)&&(x=(y)))
using namespace std;
int n,a[N+5];
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
        #define tn (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
        Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
        I void clear() {fwrite(FO,1,C,stdout),C=0;}
}F;
class ODT//ODT模板
{
    private:
        #define IT set<Il>::iterator
        #define ins insert
        #define era erase
        #define fir first
        #define LB lower_bound
        #define len(t) ((t)->r-(t)->l+1)
        struct Il//记录区间信息
        {
            int l,r;mutable int v;I Il(CI x=0,CI y=0,CI p=0):l(x),r(y),v(p){}
            I bool operator < (Con Il& t) Con {return l<t.l;}
        };set<Il> S;
        I IT Sp(CI x)//分裂操作
        {
            IT t;if((t=S.LB(Il(x)))!=S.end()&&!(t->l^x)) return t;
            --t;RI l=t->l,r=t->r,v=t->v;return S.era(t),S.ins(Il(l,x-1,v)),S.ins(Il(x,r,v)).fir;
        }
    public:
        I void Init(CI x,int* s) {for(RI i=(s[0]=s[x+1]=-1,1),t=0;i<=x+2;++i) s[i]^s[i-1]&&(S.ins(Il(t,i-1,s[i-1])),t=i);}//初始化
        I void Assign(CI x,CI y,CI v) {IT tr=Sp(y+1),tl=Sp(x);S.era(tl,tr),S.ins(Il(x,y,v));}//推平操作
        I void Inverse(CI x,CI y) {IT tr=Sp(y+1),tl=Sp(x),t=tl;W(t!=tr) (t++)->v^=1;}//区间取反
        I int QSum(CI x,CI y) {IT tr=Sp(y+1),tl=Sp(x);RI t=0;W(tl!=tr) t+=tl->v*len(tl),++tl;return t;}//区间求和
        I int QCon(CI x,CI y) {IT tr=Sp(y+1),tl=Sp(x);RI t=0,p=0;W(tl!=tr) tl->v?p+=len(tl),Gmax(t,p):p=0,++tl;return t;}//求一段区间内最多有多少连续的1
}O;
int main()
{
    RI Qtot,i,op,x,y;for(F.read(n,Qtot),i=1;i<=n;++i) F.read(a[i]);
    O.Init(n,a);W(Qtot--)
    {
        switch(F.read(op,x,y),++x,++y,op)
        {
            case 0:O.Assign(x,y,0);break;case 1:O.Assign(x,y,1);break;
            case 2:O.Inverse(x,y);break;case 3:F.writeln(O.QSum(x,y));break;
            case 4:F.writeln(O.QCon(x,y));break;
        }
    }return F.clear(),0;
}
posted @ 2019-03-18 10:15  TheLostWeak  阅读(1057)  评论(0编辑  收藏  举报