zoukankan      html  css  js  c++  java
  • Solution -「LOJ #6029」「雅礼集训 2017」市场

    (mathcal{Description})

      Link.

      维护序列 (lang a_n ang),支持 (q) 次如下操作:

    1. 区间加法;

    2. 区间下取整除法;

    3. 区间求最小值;

    4. 区间求和。

      (n,qle10^5),值域大约是 (V=2 imes10^9)

    (mathcal{Solution})

      可以推测是势能线段树。对于线段树上的区间 ([l,r]),想要将它 (div d),维护 (u=min_{i=l}^r{a_i}) 以及 (v=max_{i=l}^r{a_i}),当 (lfloorfrac{u}{d} floor-u=lfloorfrac{v}{d} floor-v) 时直接打区间加法标记,否则递归处理。其他操作正常在线段树上进行,若不考虑各变量间的数量级关系,可证复杂度为 (mathcal O((n+qlog n)log V))

    证明   设线段树上区间 $[l,r]$ 有势能 $Phi[l,r]=log(v-u)$($v,u$ 定义如上),总势能 $Phi=sumPhi[l,r]$,则:
    • 初始状态,(Phi[l,r]lemathcal O(log V))(Philemathcal O(nlog V))
    • 区间加法,势能有变动的区间个数为 (mathcal O(log n))(DeltaPhi[l,r]lemathcal O(log V)),故 (DeltaPhi=sumDeltaPhi[l,r]lemathcal O(log nlog V))
    • 区间除法,设操作对象为区间 ([s,e]),首先其有基础复杂度开销 (mathcal O(log n)),也有可能带来至多 (mathcal O(log nlog V)) 的势能增加。考虑树上一个被它完全覆盖的区间 ([l,r])。若在这个区间需要向下递归,则必然有 (DeltaPhi[l,r]le-1),所以 (DeltaPhipropto x),其中 (x) 即递归入完全覆盖区间的次数。那么本次操作的复杂度为 (mathcal O(log n+x))

      综上,总复杂度为 (mathcal O(qlog n)+sum x),即 (mathcal O(qlog n+nlog V+qlog nlog V)),当然第一项可以忽略。 (square)

    (mathcal{Code})

    /*~Rainybunny~*/
    
    #include <cmath>
    #include <cstdio>
    
    #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
    #define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
    
    typedef long long LL;
    #define int LL
    
    inline int rint() {
        int x = 0, f = 1, s = getchar();
        for ( ; s < '0' || '9' < s; s = getchar() ) f = s == '-' ? -f : f;
        for ( ; '0' <= s && s <= '9'; s = getchar() ) x = x * 10 + ( s ^ '0' );
        return x * f;
    }
    
    template<typename Tp>
    inline void wint( Tp x ) {
        if ( x < 0 ) putchar( '-' ), x = -x;
        if ( 9 < x ) wint( x / 10 );
        putchar( x % 10 ^ '0' );
    }
    
    inline int imin( const int a, const int b ) { return a < b ? a : b; }
    inline int imax( const int a, const int b ) { return a < b ? b : a; }
    
    const int MAXN = 1e5, IINF = 1ll << 60;
    int n, q;
    
    struct SegmentTree {
        int len[MAXN << 2], mx[MAXN << 2], mn[MAXN << 2], adt[MAXN << 2];
        LL sum[MAXN << 2];
    
        inline void pushup( const int u ) {
            mx[u] = imax( mx[u << 1], mx[u << 1 | 1] );
            mn[u] = imin( mn[u << 1], mn[u << 1 | 1] );
            sum[u] = sum[u << 1] + sum[u << 1 | 1];
        }
    
    
        inline void pushad( const int u, const int v ) {
            adt[u] += v, mn[u] += v, mx[u] += v, sum[u] += 1ll * v * len[u];
        }
    
        inline void pushdn( const int u ) {
            if ( adt[u] ) {
                pushad( u << 1, adt[u] ), pushad( u << 1 | 1, adt[u] );
                adt[u] = 0;
            }
        }
    
        inline void build( const int u, const int l, const int r ) {
            len[u] = r - l + 1;
            if ( l == r ) return void( mx[u] = mn[u] = sum[u] = rint() );
            int mid = l + r >> 1;
            build( u << 1, l, mid ), build( u << 1 | 1, mid + 1, r );
            pushup( u );
        }
    
        inline void add( const int u, const int l, const int r,
          const int al, const int ar, const int v ) {
            if ( al <= l && r <= ar ) return pushad( u, v );
            int mid = l + r >> 1; pushdn( u );
            if ( al <= mid ) add( u << 1, l, mid, al, ar, v );
            if ( mid < ar ) add( u << 1 | 1, mid + 1, r, al, ar, v );
            pushup( u );
        }
    
        inline void div( const int u, const int l, const int r,
          const int dl, const int dr, const int v ) {
            // if ( v == 1 ) return ;
            if ( dl <= l && r <= dr && mx[u] - floor( 1. * mx[u] / v )
              == mn[u] - floor( 1. * mn[u] / v ) ) {
                return pushad( u, floor( 1. * mx[u] / v ) - mx[u] );
            }
            int mid = l + r >> 1; pushdn( u );
            if ( dl <= mid ) div( u << 1, l, mid, dl, dr, v );
            if ( mid < dr ) div( u << 1 | 1, mid + 1, r, dl, dr, v );
            pushup( u );
        }
    
        inline int qmin( const int u, const int l, const int r,
          const int ql, const int qr ) {
            if ( ql <= l && r <= qr ) return mn[u];
            int mid = l + r >> 1, ret = IINF; pushdn( u );
            if ( ql <= mid ) ret = imin( ret, qmin( u << 1, l, mid, ql, qr ) );
            if ( mid < qr )
                ret = imin( ret, qmin( u << 1 | 1, mid + 1, r, ql, qr ) );
            return ret;
        }
    
        inline LL qsum( const int u, const int l, const int r,
          const int ql, const int qr ) {
            if ( ql <= l && r <= qr ) return sum[u];
            int mid = l + r >> 1; LL ret = 0; pushdn( u );
            if ( ql <= mid ) ret += qsum( u << 1, l, mid, ql, qr );
            if ( mid < qr ) ret += qsum( u << 1 | 1, mid + 1, r, ql, qr );
            return ret;
        }
    } sgt;
    
    signed main() {
        n = rint(), q = rint();
        sgt.build( 1, 0, n - 1 );
        for ( int op, l, r; q--; ) {
            op = rint(), l = rint(), r = rint();
            if ( op == 1 ) sgt.add( 1, 0, n - 1, l, r, rint() );
            else if ( op == 2 ) sgt.div( 1, 0, n - 1, l, r, rint() );
            else if ( op == 3 ) wint( sgt.qmin( 1, 0, n - 1, l, r ) ), puts( "" );
            else wint( sgt.qsum( 1, 0, n - 1, l, r ) ), puts( "" );
        }
        return 0;
    }
    
    
  • 相关阅读:
    Flask 入门(十二)
    Flask 入门(特别篇)
    Flask 入门 (十一)
    Flask 入门(十)
    Flask 入门(九)
    [20171031]markhot.txt
    [20170927]关于hugepages.txt
    [20170927]hugepages与内核参数nr_overcommit_hugepages.txt
    [20170916]sqlplus set array最小2补充.txt
    [20170914]tnsnames.ora的管理.txt
  • 原文地址:https://www.cnblogs.com/rainybunny/p/15177751.html
Copyright © 2011-2022 走看看