线段树练习-懒惰标记的应用

版权声明:本文为博主原创文章,未经博主允许也可以转载。 https://blog.csdn.net/FrankAx/article/details/81980026

题目链接
题意:2个操作:
1:l,r,x,数组1区间l-r全部由y(初始为对应位置 i )变为x,此时数组2每个位置加上|x-y|。
2: l , r 询问数组2 的 l - r 的和。
思路:可以把数组1和2放到一个线段树维护更新(当然开两个也是可以的),col为数组1,sum为数组2,对于数组1,两个儿子颜色相同才能有颜色。对于数组2,就是求和。
懒惰标记记录每次更新后节点颜色与更新颜色的差值。
需要注意的是中间会爆int

#include <bits/stdc++.h>
#define LL long long 
using namespace std;
const int AX = 1e5+66;
int tot ;
struct Node{
    int col ;
    LL sum ;
    LL lazy ;
}s[AX<<2];

void pushUp( int rt ){
    s[rt].sum = s[rt<<1].sum + s[rt<<1|1].sum ;
    if( s[rt<<1].col == s[rt<<1|1].col ){
        s[rt].col = s[rt<<1].col;   
    }else s[rt].col = 0 ; 
    return ;  
}

void pushDown( int rt , int L , int R ){
    if( s[rt].col && s[rt].lazy ){
        int mid = ( L + R ) >> 1 ;
        s[rt<<1].col = s[rt].col ;
        s[rt<<1|1].col = s[rt].col ;
        s[rt<<1].sum += ( mid - L + 1 ) * s[rt].lazy ;
        s[rt<<1|1].sum += ( R - mid ) * s[rt].lazy ;
        s[rt<<1].lazy += s[rt].lazy;
        s[rt<<1|1].lazy += s[rt].lazy;
        s[rt].lazy = 0 ;
    }
    return ;
}

void build( int l , int r , int rt ){
    if( l == r ){
        s[rt].col = ++tot;
        return ; 
    }
    int mid = ( l + r ) >> 1 ;
    build( l , mid , rt << 1 );
    build( mid + 1 , r , rt << 1 | 1 );
    pushUp(rt);
}

void update( int L , int R , int v , int l , int r , int rt ){
    if( L <= l && R >= r && s[rt].col ){
        s[rt].sum += (LL)((LL)( r - l + 1 ) * (LL)abs( v - s[rt].col ));
        s[rt].lazy += abs( v - s[rt].col );
        s[rt].col = v;
        return;
    }
    pushDown( rt , l , r );
    int mid = ( l + r ) >> 1 ;
    if( L <= mid ) update( L , R , v , l , mid , rt << 1 );
    if( R > mid ) update( L , R , v , mid + 1 , r , rt << 1 | 1 );
    pushUp(rt);
}

LL query( int L , int R , int l , int r , int rt ){
    if( L <= l && R >= r ){
        return s[rt].sum;
    }
    pushDown( rt , l , r );
    LL ans = 0LL ;
    int mid = ( l + r ) >> 1 ;
    if( L <= mid ) ans += query( L , R , l , mid , rt << 1 );
    if( R > mid ) ans += query( L , R , mid + 1 , r , rt << 1 | 1 );
    pushUp(rt);
    return ans ;  
}

int main(){
    int n, m ; 
    int op ; 
    int l , r , x ;
    scanf("%d%d",&n,&m);
    tot = 0;
    build( 1 , n , 1 );
    while( m -- ){
        scanf("%d",&op);
        if( op == 1 ){ 
            scanf("%d%d%d",&l,&r,&x);
            update( l , r , x , 1 , n , 1 );
        }else{
            scanf("%d%d",&l,&r);
            printf("%I64d\n",query( l , r , 1 , n , 1 ) ); 
        }
    }
    return 0 ;
}

猜你喜欢

转载自blog.csdn.net/FrankAx/article/details/81980026
今日推荐