• 【题解】序列操作 & CPU监控


    序列操作

    题目链接

    Statement

    给定一个长为 (n)01 序列,要求实现 (5) 种操作:

    • 0 a b([a,b]) 全部设为 (0) .
    • 1 a b([a,b]) 全部设为 (1) .
    • 2 a b 将区间所有数取反 。
    • 3 a b 询问区间内 (1) 的个数。
    • 4 a b 询问区间内连续 (1) 的个数。

    Solution

    顶风作案写DS.jpg

    线段树恶心题,但是很经典,码得也算能看,就拿出来当板子了。

    维护前缀 (0/1) 、后缀 (0/1) 、连续 (0/1) 的个数,和区间中 (0/1) 的个数。注意覆盖标记优先级高于翻转标记。

    线段树恶心题,码就完了。实在不行,重构就是了

    好在码得并不慢,调得也很快,调过样例之后一遍就过拍了(本地数据手动 diff )。

    你谷开 O2 跑进了第二页,BZOJ 没开 O2 卡在第一页底端/youl

    希望下次写结构体函数的时候:

    (huge 真的不要再忘记return了)

    Code

    //Author: RingweEH
    //菜鸡REH顶风作案
    const int N=1e5+10;
    int n,q,a[N];
    struct SegmentTree
    {
        struct Node
        {
            int cntw,cntb,lcntw,rcntw,lcntb,rcntb,mxw,mxb;
            //w个数,b个数,左/右数w个数,左/右数b个数,连续w/b最大值
            Node( int _cntw=0,int _cntb=0,int _lcntw=0,int _lcntb=0,
                int _rcntw=0,int _rcntb=0,int _mxw=0,int _mxb=0 )
            {
                cntw=_cntw; cntb=_cntb; lcntw=_lcntw; lcntb=_lcntb;
                rcntb=_rcntb; rcntw=_rcntw; mxw=_mxw; mxb=_mxb;
            }
            Node operator + ( const Node &tmp ) const
            {
                Node res;
                res.cntw=cntw+tmp.cntw; res.cntb=cntb+tmp.cntb;
                res.lcntw=cntb ? lcntw : cntw+tmp.lcntw;
                res.lcntb=cntw ? lcntb : cntb+tmp.lcntb;
                res.rcntw=tmp.cntb ? tmp.rcntw : tmp.cntw+rcntw;
                res.rcntb=tmp.cntw ? tmp.rcntb : tmp.cntb+rcntb;
                res.mxw=max( max(mxw,tmp.mxw),rcntw+tmp.lcntw );
                res.mxb=max( max(mxb,tmp.mxb),rcntb+tmp.lcntb );
                return res;
            }
        }tr[N<<2];
        int len[N<<2],tag1[N<<2],tag2[N<<2];
        //区间长度,区间赋值标记(-1/0/1),区间取反(0/1)
        void Operate( int pos,int opt ) 
        {
            Node &te=tr[pos];
            if ( opt==0 )   //reset( 0 )
            {
                tag2[pos]=tag1[pos]=0; int t=len[pos];
                te=Node( 0,t,0,t,0,t,0,t );
            }
            if ( opt==1 )   //reset( 1 )
            {
                tag2[pos]=0,tag1[pos]=1; int t=len[pos];
                te=Node( t,0,t,0,t,0,t,0 );
            }
            if ( opt==2 )   //flip
            {
                tag2[pos]^=1; 
                swap( te.cntw,te.cntb ); swap( te.mxb,te.mxw );
                swap( te.lcntw,te.lcntb ); swap( te.rcntw,te.rcntb );
            }
        }
        void Pushdown( int pos )
        {
            if ( tag1[pos]>-1 ) 
                Operate( pos<<1,tag1[pos] ),Operate( pos<<1|1,tag1[pos] );
            if ( tag2[pos] ) 
                Operate( pos<<1,2 ),Operate( pos<<1|1,2 );
            tag1[pos]=-1; tag2[pos]=0; 
        }
        void Modify( int pos,int L,int R,int l,int r,int val )
        {
            if ( r<L || R<l ) return;
            if ( l<=L && R<=r ) { Operate( pos,val ); return; }
            Pushdown( pos ); int mid=(L+R)>>1;
            Modify( pos<<1,L,mid,l,r,val ); Modify( pos<<1|1,mid+1,R,l,r,val );
            tr[pos]=tr[pos<<1]+tr[pos<<1|1];
        }
        Node Query( int pos,int L,int R,int l,int r )
        {
            if ( r<L || R<l ) return Node();
            if ( l<=L && R<=r ) return tr[pos];
            Pushdown( pos ); int mid=(L+R)>>1;
            Node lc=Query(pos<<1,L,mid,l,r),rc=Query(pos<<1|1,mid+1,R,l,r);
            return lc+rc;
        }
        void Build( int pos,int L,int R )
        {
            len[pos]=R-L+1; tag1[pos]=-1;
            if ( L==R )
            {
                int t=a[L]; tr[pos]=Node(t,t^1,t,t^1,t,t^1,t,t^1 );
                return;
            }
            int mid=(L+R)>>1;
            Build( pos<<1,L,mid ); Build( pos<<1|1,mid+1,R );
            tr[pos]=tr[pos<<1]+tr[pos<<1|1];
        }
        int Answer( int l,int r,int opt )
        {
            Node res=Query( 1,1,n,l,r );
            if ( opt==3 ) return res.cntw;
            else return res.mxw;
        }
        //w,b,lw,lb,rw,rb,mw,mb;
    }Tr;
    
    int main()
    {
        n=read(); q=read();
        for ( int i=1; i<=n; i++ )
            a[i]=read();
    
        Tr.Build(1,1,n);
        while ( q-- )
        {
            int opt=read(),l=read()+1,r=read()+1;
            if ( opt<3 ) Tr.Modify( 1,1,n,l,r,opt );
            else printf( "%d
    ",Tr.Answer(l,r,opt) );
        }
    
        return 0;
    }
    

    CPU监控

    题目链接

    Statement

    对于一个序列,要求支持操作:

    • Q X Y 询问区间 ([X,Y]) 的最大值
    • A X Y 询问区间 ([X,Y]) 的历史最大值
    • P X Y Z 区间 ([X,Y]) 增加为 (Z)
    • C X Y Z 区间 ([X,Y]) 推平为 (Z)

    Solution

    坑点:如果照常写,会发现有些 tag 还没更新就被覆盖了,然后就出大问题。所以要多记录一个“距离上次下传到目前的增加和推平 (max) ”。

    其他就仔细点就好了。

    重构永远的神!

    //Author: RingweEH
    #define lson pos<<1
    #define rson pos<<1|1
    const int N=1e5+10,INF=0x3f3f3f3f;
    struct Node
    {
    	int val,add,assign,lasv,lasad,lasas;
    };
    void bmax( int &x,int y ) { x=(x>y) ? x : y; }
    struct SegmentTree
    {
    	Node tr[N<<2];
    	void Pushup( int pos )
    	{
    		tr[pos].val=max( tr[lson].val,tr[rson].val );
    		tr[pos].lasv=max( tr[lson].lasv,tr[rson].lasv );
    	}
    	void Upd_Add( int pos,int add,int lasad )
    	{
    		if ( tr[pos].assign!=-INF )		//有区间赋值操作
    		{
    			bmax( tr[pos].lasas,tr[pos].assign+lasad );	//遗留赋值和当前赋值+遗留add取max
    			bmax( tr[pos].lasv,tr[pos].val+lasad );		//遗留mx和当前mx+遗留add取max
    			tr[pos].assign+=add; tr[pos].val+=add;
    		}
    		else	//没有区间赋值
    		{
    			bmax( tr[pos].lasad,tr[pos].add+lasad );	//遗留add和当前add+遗留add取mx
    			bmax( tr[pos].lasv,tr[pos].val+lasad );		//遗留mx和当前mx+遗留add取mx
    			tr[pos].add+=add; tr[pos].val+=add;
    		}
    	}
    	void Upd_Assign( int pos,int ass,int lasas )
    	{
    		bmax( tr[pos].lasas,lasas );	//和当前遗留ass取max
    		bmax( tr[pos].lasv,lasas );		//更新遗留mx
    		tr[pos].assign=ass; tr[pos].val=ass;	//更新当前ass和mx
    	}
    	void Pushdown( int pos )
    	{
    		Upd_Add( lson,tr[pos].add,tr[pos].lasad );	//下放add标记
    		Upd_Add( rson,tr[pos].add,tr[pos].lasad );	
    		tr[pos].add=tr[pos].lasad=0;
    		if ( tr[pos].assign!=-INF )		//下放ass标记,因为优先级高
    		{
    			Upd_Assign( lson,tr[pos].assign,tr[pos].lasas );
    			Upd_Assign( rson,tr[pos].assign,tr[pos].lasas );
    			tr[pos].assign=tr[pos].lasas=-INF;		//注意不是赋值成0,因为有负数
    		}
    	}
    	void Modify_Add( int pos,int L,int R,int l,int r,int val )
    	{
    		if ( L>r || R<l ) return;
    		if ( l<=L && R<=r ) { Upd_Add( pos,val,val ); return; }
    		Pushdown( pos ); int mid=(L+R)>>1;
    		Modify_Add( lson,L,mid,l,r,val ); Modify_Add( rson,mid+1,R,l,r,val );
    		Pushup( pos );
    	}
    	void Modify_Ass( int pos,int L,int R,int l,int r,int val )
    	{
    		if ( L>r || R<l ) return;
    		if ( l<=L && R<=r ) { Upd_Assign( pos,val,val ); return; }
    		Pushdown( pos ); int mid=(L+R)>>1;
    		Modify_Ass( lson,L,mid,l,r,val ); Modify_Ass( rson,mid+1,R,l,r,val );
    		Pushup( pos );
    	}
    	int Query( int pos,int L,int R,int l,int r,int opt )
    	{
    		if ( L>r || R<l ) return -INF;
    		if ( l<=L && R<=r ) return opt ? tr[pos].lasv : tr[pos].val;
    		Pushdown( pos ); int mid=(L+R)>>1;
    		return max( Query( lson,L,mid,l,r,opt ),Query( rson,mid+1,R,l,r,opt ) );
    	}
    	void Build( int pos,int l,int r )
    	{
    		tr[pos].assign=tr[pos].lasas=-INF;
    		if ( l==r )
    		{
    			tr[pos].val=tr[pos].lasv=read(); return;
    		}
    		int mid=(l+r)>>1;
    		Build( lson,l,mid ); Build( rson,mid+1,r );
    		Pushup( pos );
    	}
    }Tr;
    char ch[5];
    
    int main()
    {
    	int n=read(); Tr.Build(1,1,n); int q=read();
    	while( q-- )
    	{
    		scanf( "%s",ch ); int x=read(),y=read(),z;
    		if ( ch[0]=='Q' ) printf( "%d
    ",Tr.Query(1,1,n,x,y,0) );
    		else if ( ch[0]=='A' ) printf( "%d
    ",Tr.Query(1,1,n,x,y,1) );
    		else if ( ch[0]=='P' ) z=read(),Tr.Modify_Add(1,1,n,x,y,z);
    		else z=read(),Tr.Modify_Ass(1,1,n,x,y,z);
    	}
        return 0;
    }
    
  • 相关阅读:
    Spring注解驱动开发3:自动装配
    Spring注解驱动开发2:生命周期和属性赋值
    Spring注解驱动开发1:组件注册
    Java线程及其实现方式
    Winform 可取消的单选按钮(RadioButton)
    autoit脚本-从基本的函数用法开始
    python进阶(一)
    dict字典的一些优势和劣势
    读《流畅的python》第一天
    智能化脚本autoit v3的简单了解
  • 原文地址:https://www.cnblogs.com/UntitledCpp/p/SegmentTreePlus.html
Copyright © 2020-2023  润新知