[BZOJ4280]-[ONTAK2015]Stumilowy sad-线段树

说在前面

并没有什么想说的,但是要保持格式=w=


题目

BZOJ4280传送门

题目大意

给出一个长为 N N 的数字序列,你需要维护下列四个操作

  1. L R x:给 L L R 的所有数字加上 x x ,保证|x|500

    • L R x L   R   x :让 L L R 的所有数字对 x x 取max,即所有 a[i] 变成 max(a[i],x) max ( a [ i ] , x )
    • L R x L   R   x :让 L L R 的所有数字对 x x 取min,即所有 a[i] 变成 min(a[i],x) min ( a [ i ] , x )
    • L R L   R :询问区间 [L,R] [ L , R ] 的最大值
    • 范围: N500000 N ≤ 500000 a[i]109 a [ i ] ≤ 10 9

      输入输出格式

      输入格式:
      第一行两个整数 N,Q N , Q ,表示序列长度和操作个数
      接下来一行 N N 个整数描述初始的序列
      再接下来 Q 行,每行描述一个操作,在操作前会有操作编号,形如 1 1 1 2 1   1   1   2 表示 L=1,R=1,x=2 L = 1 , R = 1 , x = 2 的第一种操作

      输出格式:
      对于每个询问操作,输出答案


      解法

      主要就是复合标记的维护
      这里me的维护方式是:先取min/max,再执行加法
      维护还是比较好想的

      有一个注意的地方,就是当max标记已经比min标记还大的时候,原来的min标记仍然是有用的,需要把min标记改成max一样大小,而不是直接删掉。me一开始就错在这个地方了


      下面是代码

      /**************************************************************
          Problem: 4280
          User: Izumihanako
          Language: C++
          Result: Accepted
          Time:6868 ms
          Memory:30120 kb
      ****************************************************************/
      
      #include <cstdio>
      #include <cstring>
      #include <algorithm>
      using namespace std ;
      
      int N , Q , h[500005] ;
      struct Node{
          int maxn , flag_add , flag_mx/* down */ , flag_mn/* up */ ;
          bool mx , mn ;
          Node *ch[2] ;
          void chMin( int now ){
              maxn = min( maxn , now ) ;
              if( !mn || flag_mn > now - flag_add ){
                  flag_mn = now - flag_add , mn = true ;
                  if( mx && flag_mx >= flag_mn ) flag_mx = flag_mn ;
              }
          }
          void chMax( int now ){
              maxn = max( maxn , now ) ;
              if( !mx || flag_mx < now - flag_add ){
                  flag_mx = now - flag_add , mx = true ;
                  if( mn && flag_mn <= flag_mx ) flag_mn = flag_mx ;
              }
          }
          void add( int delta ){
              maxn += delta ;
              flag_add += delta ;
          }
          void update(){
              maxn = max( ch[0]->maxn , ch[1]->maxn ) ;
          }
          void pushdown(){
              if( mn ){
                  ch[0]->chMin( flag_mn ) ;
                  ch[1]->chMin( flag_mn ) ;
                  mn = false ;
              } if( mx ){
                  ch[0]->chMax( flag_mx ) ;
                  ch[1]->chMax( flag_mx ) ;
                  mx = false ;
              } if( flag_add ){
                  ch[0]->add( flag_add ) ;
                  ch[1]->add( flag_add ) ;
                  flag_add = 0 ;
              }
          }
      }w[1000005] , *tw = w , *root ;
      
      Node *build( int lf , int rg ){
          Node *nd = ++ tw ;
          if( lf == rg ){
              nd->maxn = h[lf] ;
              return nd ;
          } int mid = ( lf + rg ) >> 1 ;
          nd->ch[0] = build( lf , mid ) ;
          nd->ch[1] = build( mid+1,rg ) ;
          nd->update() ; return nd ;
      }
      
      void Add( Node *nd , int lf , int rg , int L , int R , int x ){
          if( L <= lf && rg <= R ){ nd->add( x ) ; return ; }
          int mid = ( lf + rg ) >> 1 ;
          nd->pushdown() ;
          if( L <= mid ) Add( nd->ch[0] , lf , mid , L , R , x ) ;
          if( R >  mid ) Add( nd->ch[1] , mid+1,rg , L , R , x ) ;
          nd->update() ;
      }
      
      void Min( Node *nd , int lf , int rg , int L , int R , int x ){
          if( L <= lf && rg <= R ){ nd->chMin( x ) ; return ; }
          int mid = ( lf + rg ) >> 1 ;
          nd->pushdown() ;
          if( L <= mid ) Min( nd->ch[0] , lf , mid , L , R , x ) ;
          if( R >  mid ) Min( nd->ch[1] , mid+1,rg , L , R , x ) ;
          nd->update() ;
      }
      
      void Max( Node *nd , int lf , int rg , int L , int R , int x ){
          if( L <= lf && rg <= R ){ nd->chMax( x ) ; return ; }
          int mid = ( lf + rg ) >> 1 ;
          nd->pushdown() ;
          if( L <= mid ) Max( nd->ch[0] , lf , mid , L , R , x ) ;
          if( R >  mid ) Max( nd->ch[1] , mid+1,rg , L , R , x ) ;
          nd->update() ;
      }
      
      int Query( Node *nd , int lf , int rg , int L , int R ){
          if( L <= lf && rg <= R ) return nd->maxn ;
          int mid = ( lf + rg ) >> 1 , rt = -0x3f3f3f3f ;
          nd->pushdown() ;
          if( L <= mid ) rt = max( rt , Query( nd->ch[0] , lf , mid , L , R ) ) ;
          if( R >  mid ) rt = max( rt , Query( nd->ch[1] , mid+1,rg , L , R ) ) ;
          return rt ;
      }
      
      void solve(){
          root = build( 1 , N ) ;
          for( int i = 1 , o , l , r , x ; i <= Q ; i ++ ){
              scanf( "%d%d%d" , &o , &l , &r ) ;
              if( o <= 3 ){
                  scanf( "%d" , &x ) ;
                  if( o == 1 ) Add( root , 1 , N , l , r , x ) ;
                  else if( o == 2 ) Min( root , 1 , N , l , r , x ) ; 
                  else Max( root , 1 , N , l , r , x ) ;
              } else printf( "%d\n" , Query( root , 1 , N , l , r ) ) ;
          }
      }
      
      int main(){
          scanf( "%d%d" , &N , &Q ) ;
          for( int i = 1 ; i <= N ; i ++ )
              scanf( "%d" , &h[i] ) ;
          solve() ;
      }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值