说在前面
并没有什么想说的,但是要保持格式=w=
题目
题目大意
给出一个长为 N N 的数字序列,你需要维护下列四个操作
- :给
L
L
到 的所有数字加上
x
x
,保证
- L R x L R x :让 L L 到 的所有数字对 x x 取max,即所有 变成 max(a[i],x) max ( a [ i ] , x )
- L R x L R x :让 L L 到 的所有数字对 x x 取min,即所有 变成 min(a[i],x) min ( a [ i ] , x )
- L R L R :询问区间 [L,R] [ L , R ] 的最大值
范围: N≤500000 N ≤ 500000 , a[i]≤109 a [ i ] ≤ 10 9
输入输出格式
输入格式:
第一行两个整数 N,Q N , Q ,表示序列长度和操作个数
接下来一行 N N 个整数描述初始的序列
再接下来 行,每行描述一个操作,在操作前会有操作编号,形如 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() ; }