• Solution -「LOCAL」ZB 平衡树


    (mathcal{Description})

      OurOJ.

      维护一列二元组 ((a,b)),给定初始 (n) 个元素,接下来 (m) 次操作:

    1. 在某个位置插入一个二元组;

    2. 翻转一个区间;

    3. 区间 (a) 值加上一个数;

    4. 区间 (a) 值乘上一个数;

    5. 区间 (a) 值赋为一个数;

    6. 询问 (sum_{i=l}^rsum_{j=i}^ra_j^3mod10086001)

      特别地,若区间操作指名类型为 (1),则需要将输入的左端点替换为输入区间内次大二元组 ((b_i,i))(i)(二元组传统偏序关系比较;保证存在)。

      (n,mle2 imes10^5)

    (mathcal{Solution})

      出题人都写不对的码农题系列。(

      很明显 (a) 的维护和 (b) 的维护完全不相关,先考虑处理 (a) 上的操作。区间加法和一个次数不算高的幂和,提示我们暴力维护 (0sim3) 次幂和来处理修改。所以维护一个阶梯幂和(值 ( imes)下标,应对“后缀和之和”的询问),和一个普通幂和(乘若干倍后与前者相减就能做到翻转区间)。

      对于 (b),直接维护次大值相关信息非常麻烦。可以考虑仅维护最大值,然后利用非旋 Treap 的操作处理。首先,找到区间最大值,把树裂乘最大值左侧树和最大值右侧树,分别在两棵树里找最大值,显然次大值比为其中之一。

      于是 (mathcal O((n+m)log(n+m))) 就口胡完了,至于 (8K+) 的码量嘛……/xyx

    (mathcal{Code})

    /* Clearink */
    
    #include <cstdio>
    #include <cassert>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    
    #define rep( i, l, r ) for ( int i = l, repEnd##i = r; i <= repEnd##i; ++i )
    #define per( i, r, l ) for ( int i = r, repEnd##i = l; i >= repEnd##i; --i )
    
    inline int rint () {
    	int x = 0, f = 1; char 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' );
    }
    
    const int MAXN = 4e5, MOD = 10086001, INF = ( 1ll << 31 ) - 1;
    int n, q, a[MAXN + 5];
    
    inline void iswp ( int& a, int& b ) { a ^= b ^= a ^= b; }
    inline void muleq ( int& a, const int b ) { a = 1ll * a * b % MOD; }
    inline int mul ( const long long a, const int b ) { return a * b % MOD; }
    inline int sub ( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
    inline int add ( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
    inline void addeq ( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD, 0 ); }
    inline int imax ( const int a, const int b ) { return a < b ? b : a; }
    inline int imin ( const int a, const int b ) { return a < b ? a : b; }
    inline int sqr ( const int n ) { return ( n * ( n + 1ll ) >> 1 ) % MOD; }
    
    struct Cube {
    	int pwr[3];
    	Cube (): pwr {} {}
    	Cube ( const int v ): pwr { v, mul ( v, v ), mul ( v, mul ( v, v ) ) } {}
    	Cube ( const int v1, const int v2, const int v3 ): pwr { v1, v2, v3 } {}
    	inline int& operator [] ( const int k ) { return pwr[k]; }
    	inline Cube operator + ( Cube c ) const {
    		return {
    			add ( pwr[0], c[0] ), add ( pwr[1], c[1] ), add ( pwr[2], c[2] )
    		};
    	}
    	inline Cube operator - ( Cube& c ) const {
    		return {
    			sub ( pwr[0], c[0] ), sub ( pwr[1], c[1] ), sub ( pwr[2], c[2] )
    		};
    	}
    	inline Cube operator * ( const int c ) const {
    		return {
    			mul ( pwr[0], c ), mul ( pwr[1], c ), mul ( pwr[2], c )
    		};
    	}
    	inline Cube operator * ( Cube c ) const {
    		return {
    			mul ( pwr[0], c[0] ), mul ( pwr[1], c[1] ), mul ( pwr[2], c[2] )
    		};
    	}
    };
    
    struct NRTreap {
    	int node, root, ch[MAXN + 5][2], key[MAXN + 5], siz[MAXN + 5];
    	int a[MAXN + 5], b[MAXN + 5], zb[MAXN + 5];
    	Cube sum[MAXN + 5], lad[MAXN + 5];
    	int asgt[MAXN + 5], mult[MAXN + 5], addt[MAXN + 5];
    	bool revt[MAXN + 5];
    
    	NRTreap (): zb { -INF } { srand ( 20120712 ); }
    
    	inline int crtnd ( const int va, const int vb ) {
    		int u = ++node;
    		key[u] = rand (), siz[u] = 1;
    		lad[u] = sum[u] = a[u] = va;
    		zb[u] = b[u] = vb;
    		asgt[u] = INF, mult[u] = 1, addt[u] = revt[u] = 0;
    		return u;
    	}
    
    	inline void pushrv ( const int x ) {
    		revt[x] ^= 1, ch[x][0] ^= ch[x][1] ^= ch[x][0] ^= ch[x][1];
    		lad[x] = sum[x] * ( siz[x] + 1 ) - lad[x];
    	}
    
    	inline void pushas ( const int x, const int v ) {
    		a[x] = asgt[x] = v, mult[x] = 1, addt[x] = 0;
    		sum[x] = Cube ( v ) * siz[x], lad[x] = Cube ( v ) * sqr ( siz[x] );
    	}
    
    	inline void pushmu ( const int x, const int v ) {
    		muleq ( a[x], v ), muleq ( mult[x], v ), muleq ( addt[x], v );
    		sum[x] = sum[x] * Cube ( v );
    		lad[x] = lad[x] * Cube ( v );
    	}
    
    	inline void pushad ( const int x, const int v1 ) {
    		int v2 = mul ( v1, v1 ), v3 = mul ( v2, v1 );
    		addeq ( a[x], v1 ), addeq ( addt[x], v1 );
    
    		addeq ( lad[x][2], mul ( sqr ( siz[x] ), v3 ) );
    		addeq ( lad[x][2], mul ( mul ( 3, v2 ), lad[x][0] ) );
    		addeq ( lad[x][2], mul ( mul ( 3, v1 ), lad[x][1] ) );
    		addeq ( lad[x][1], mul ( sqr ( siz[x] ), v2 ) );
    		addeq ( lad[x][1], mul ( mul ( 2, v1 ), lad[x][0] ) );
    		addeq ( lad[x][0], mul ( sqr ( siz[x] ), v1 ) );
    
    		addeq ( sum[x][2], mul ( siz[x], v3 ) );
    		addeq ( sum[x][2], mul ( mul ( 3, v2 ), sum[x][0] ) );
    		addeq ( sum[x][2], mul ( mul ( 3, v1 ), sum[x][1] ) );
    		addeq ( sum[x][1], mul ( siz[x], v2 ) );
    		addeq ( sum[x][1], mul ( mul ( 2, v1 ), sum[x][0] ) );
    		addeq ( sum[x][0], mul ( siz[x], v1 ) );
    	}
    
    	inline void pushdn ( const int x ) {
    		if ( revt[x] ) {
    			if ( ch[x][0] ) pushrv ( ch[x][0] );
    			if ( ch[x][1] ) pushrv ( ch[x][1] );
    			revt[x] = 0;
    		}
    		if ( asgt[x] != INF ) {
    			if ( ch[x][0] ) pushas ( ch[x][0], asgt[x] );
    			if ( ch[x][1] ) pushas ( ch[x][1], asgt[x] );
    			asgt[x] = INF;
    		}
    		if ( mult[x] != 1 ) {
    			if ( ch[x][0] ) pushmu ( ch[x][0], mult[x] );
    			if ( ch[x][1] ) pushmu ( ch[x][1], mult[x] );
    			mult[x] = 1;
    		}
    		if ( addt[x] ) {
    			if ( ch[x][0] ) pushad ( ch[x][0], addt[x] );
    			if ( ch[x][1] ) pushad ( ch[x][1], addt[x] );
    			addt[x] = 0;
    		}
    	}
    
    	inline void pushup ( const int x ) {
    		siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;
    		zb[x] = imax ( b[x], imax ( zb[ch[x][0]], zb[ch[x][1]] ) );
    		sum[x] = sum[ch[x][0]] + a[x] + sum[ch[x][1]];
    		lad[x] = lad[ch[x][0]] + Cube ( a[x] ) * ( siz[ch[x][0]] + 1 )
    			+ lad[ch[x][1]] + sum[ch[x][1]] * ( siz[ch[x][0]] + 1 );
    	}
    
    	inline int merge ( const int x, const int y ) {
    		if ( !x || !y ) return x | y;
    		pushdn ( x ), pushdn ( y );
    		if ( key[x] < key[y] ) {
    			ch[x][1] = merge ( ch[x][1], y ), pushup ( x );
    			return x;
    		} else {
    			ch[y][0] = merge ( x, ch[y][0] ), pushup ( y );
    			return y;
    		}
    	}
    
    	inline void rsplit ( const int r, const int k, int& x, int& y ) {
    		if ( !r ) return void ( x = y = 0 );
    		pushdn ( r );
    		if ( k <= siz[ch[r][0]] ) y = r, rsplit ( ch[r][0], k, x, ch[r][0] );
    		else x = r, rsplit ( ch[r][1], k - siz[ch[r][0]] - 1, ch[r][1], y );
    		pushup ( r );
    	}
    
    	inline void insert ( const int p, const int va, const int vb ) {
    		int x, y; rsplit ( root, p, x, y );
    		root = merge ( x, merge ( crtnd ( va, vb ), y ) );
    	}
    
    #define extract() ( rsplit ( root, l - 1, x, y ), rsplit ( y, r - l + 1, y, z ) )
    	inline void reverse ( const int l, const int r ) {
    		int x, y, z; extract ();
    		if ( y ) pushdn ( y ), pushrv ( y );
    		root = merge ( x, merge ( y, z ) );
    	}
    
    	inline void addsec ( const int l, const int r, const int v ) {
    		int x, y, z; extract ();
    		if ( y ) pushdn ( y ), pushad ( y, v );
    		root = merge ( x, merge ( y, z ) );
    	}
    
    	inline void mulsec ( const int l, const int r, const int v ) {
    		int x, y, z; extract ();
    		if ( y ) pushdn ( y ), pushmu ( y, v );
    		root = merge ( x, merge ( y, z ) );
    	}
    
    	inline void asgsec ( const int l, const int r, const int v ) {
    		int x, y, z; extract ();
    		if ( y ) pushdn ( y ), pushas ( y, v );
    		root = merge ( x, merge ( y, z ) );
    	}
    
    	inline int query ( const int l, const int r ) {
    		int x, y, z, ret; extract ();
    		ret = lad[y][2], root = merge ( x, merge ( y, z ) );
    		return ret;
    	}
    #undef extract
    	inline int maxrk ( const int r ) {
    		int u = r, mx = zb[r], ret = 0;
    		while ( u ) {
    			pushdn ( u );
    			if ( zb[ch[u][0]] == mx ) u = ch[u][0];
    			else {
    				ret += siz[ch[u][0]] + 1;
    				if ( b[u] == mx ) return ret;
    				else u = ch[u][1];
    			}
    		}
    		return assert ( false ), -1;
    	}
    
    	inline int smaxrk ( const int l, const int r ) {
    		int p, x, y, z, q, ret;
    		rsplit ( root, l - 1, p, x );
    		rsplit ( x, r - l + 1, x, q );
    		rsplit ( x, maxrk ( x ) - 1, x, y );
    		rsplit ( y, 1, y, z );
    		assert ( siz[y] == 1 && ( zb[x] > -INF || zb[z] > -INF ) );
    		if ( zb[x] >= zb[z] ) ret = l - 1 + maxrk ( x );
    		else ret = l - 1 + siz[x] + 1 + maxrk ( z );
    		root = merge ( p, merge ( x, merge ( y, merge ( z, q ) ) ) );
    		#ifdef RYBY
    			printf ( "s(%d,%d)=%d
    ", l, r, ret );
    		#endif
    		return ret;
    	}
    } trp;
    
    int main () {
    	n = rint (), q = rint ();
    	rep ( i, 1, n ) a[i] = rint () % MOD;
    	rep ( i, 1, n ) {
    		trp.root = trp.merge ( trp.root, trp.crtnd ( a[i], rint () ) );
    	}
    	for ( int tp, op, l, r; q--; ) {
    		tp = rint (), op = rint (), l = rint (), r = rint ();
    		if ( op == 1 ) { trp.insert ( l, ( r + MOD ) % MOD, rint () ); continue; }
    		if ( tp ) l = trp.smaxrk ( l, r );
    		if ( op == 2 ) { trp.reverse ( l, r ); continue; }
    		if ( op == 3 ) { trp.addsec ( l, r, ( rint () + MOD ) % MOD ); continue; }
    		if ( op == 4 ) { trp.mulsec ( l, r, ( rint () + MOD ) % MOD ); continue; }
    		if ( op == 5 ) { trp.asgsec ( l, r, ( rint () + MOD ) % MOD ); continue; }
    		wint ( trp.query ( l, r ) ), putchar ( '
    ' );
    	}
    	return 0;
    }
    
    /*
    	1 2 3 14 15 16 7 8 9 10 ||| 3 2 5 7 9 1 4 2 7 10
    	
     */
    
    
  • 相关阅读:
    在阿里云“专有网络”网络类型中配置vsftpd
    Ubuntu 16.04下开启Mysql 3306端口远程访问
    .net core 2.0 报错:error NU1102: Unable to find package ...
    .NET Core Runtime ARM32 builds now available
    .NET Core on Raspberry Pi
    .NET Core 跨平台发布(dotnet publish)
    使用vscode开发调试.net core应用程序并部署到Linux跨平台
    docker容器镜像删除
    使用阿里docker镜像加速器加速
    树莓派3b基于UbuntuMate下载中文输入法
  • 原文地址:https://www.cnblogs.com/rainybunny/p/14342293.html
Copyright © 2020-2023  润新知