\(\mathcal{Description}\)

  OurOJ.

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

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

  2. 翻转一个区间;

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

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

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

  6. 询问 \(\sum_{i=l}^r\sum_{j=i}^ra_j^3\bmod10086001\)。

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

  \(n,m\le2\times10^5\)。

\(\mathcal{Solution}\)

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

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

  对于 \(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\n", 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 ( '\n' );
}
return 0;
} /*
1 2 3 14 15 16 7 8 9 10 ||| 3 2 5 7 9 1 4 2 7 10 */

Solution -「LOCAL」ZB 平衡树的更多相关文章

  1. Solution -「LOCAL」二进制的世界

    \(\mathcal{Description}\)   OurOJ.   给定序列 \(\{a_n\}\) 和一个二元运算 \(\operatorname{op}\in\{\operatorname{ ...

  2. Solution -「LOCAL」大括号树

    \(\mathcal{Description}\)   OurTeam & OurOJ.   给定一棵 \(n\) 个顶点的树,每个顶点标有字符 ( 或 ).将从 \(u\) 到 \(v\) ...

  3. Solution -「LOCAL」过河

    \(\mathcal{Description}\)   一段坐标轴 \([0,L]\),从 \(0\) 出发,每次可以 \(+a\) 或 \(-b\),但不能越出 \([0,L]\).求可达的整点数. ...

  4. Solution -「LOCAL」Drainage System

    \(\mathcal{Description}\)   合并果子,初始果子的权值在 \(1\sim n\) 之间,权值为 \(i\) 的有 \(a_i\) 个.每次可以挑 \(x\in[L,R]\) ...

  5. Solution -「LOCAL」Burning Flowers

      灼之花好评,条条生日快乐(假装现在 8.15)! \(\mathcal{Description}\)   给定一棵以 \(1\) 为根的树,第 \(i\) 个结点有颜色 \(c_i\) 和光亮值 ...

  6. Solution -「LOCAL」画画图

    \(\mathcal{Description}\)   OurTeam.   给定一棵 \(n\) 个点的树形随机的带边权树,求所有含奇数条边的路径中位数之和.树形生成方式为随机取不连通两点连边直到全 ...

  7. Solution -「LOCAL」舟游

    \(\mathcal{Description}\)   \(n\) 中卡牌,每种三张.对于一次 \(m\) 连抽,前 \(m-1\) 次抽到第 \(i\) 种的概率是 \(p_i\),第 \(m\) ...

  8. Solution -「LOCAL」充电

    \(\mathcal{Description}\)   给定 \(n,m,p\),求序列 \(\{a_n\}\) 的数量,满足 \((\forall i\in[1,n])(a_i\in[1,m])\l ...

  9. Solution -「LOCAL」「cov. 牛客多校 2020 第五场 C」Easy

    \(\mathcal{Description}\)   Link.(完全一致)   给定 \(n,m,k\),对于两个长度为 \(k\) 的满足 \(\left(\sum_{i=0}^ka_i=n\r ...

随机推荐

  1. Go语言系列之标准库strconv

    Go语言中strconv包实现了基本数据类型和其字符串表示的相互转换. strconv包 strconv包实现了基本数据类型与其字符串表示的转换,主要有以下常用函数: Atoi().Itia().pa ...

  2. Vue系列教程(三)之vue-cli脚手架的使用

    一.Vue-cli的环境准备 目的:(1)快速管理依赖 (2)确定项目结构 1.安装node.js Node.js是一个可以让前端运行在服务器上的一个工. 下载:https://nodejs.org/ ...

  3. 01-JS中字面量与变量

    01-JS中字面量与变量 一.直接量(字面量) 字面量:英语叫做literals,也做直接量,看见什么,它就是什么. (一)数字的字面量 数字的字面量,就是这个数字自己,并不需要任何的符号来界定这个数 ...

  4. conda : 无法将“conda”项识别为 cmdlet、函数、脚本文件或可运行程序的名称

    conda : 无法将"conda"项识别为 cmdlet.函数.脚本文件或可运行程序的名称.请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次. 解决办法: 没有添加系 ...

  5. 【C++】指针和函数

    指针和函数 标签:c++ 目录 指针和函数 一.基本概念 定义: 指针的定义及使用: 二.指针的相互赋值 三.指针的运算 比较大小: 相减: 加减整数类型变量或者常量: 自增自减: 下标运算符[ ]: ...

  6. 一文读懂HarmonyOS服务卡片怎么换肤

    作者:zhenyu,华为软件开发工程师 关注HarmonyOS的小伙伴肯定对服务卡片已经很熟悉了.服务卡片(也简称为"卡片")是FA(FeatureAbility,元服务)的一种界 ...

  7. 论文解读GALA《Symmetric Graph Convolutional Autoencoder for Unsupervised Graph Representation Learning》

    论文信息 Title:<Symmetric Graph Convolutional Autoencoder for Unsupervised Graph Representation Learn ...

  8. 关于C++11共享数据带来的死锁问题的提出与解决

    举个例子,如果有一份资源,假如为list<int>资源,假设有两个线程要对该资源进行压入弹出操作,如果不进行锁的话,那么如果两个线程同时操作,那么必然乱套,得到的结果肯定不是我们想要的结果 ...

  9. HTML 页面的动态线条背景-三岁

    保存一个自己正在用的背景 会跟随鼠标变换的动态线条 以免后面还得找 挺好看的 效果图: 代码如下: <script type="text/javascript" color= ...

  10. kubernetes之配置Metrics Server

    Kubernetes 1.8 关于资源使用情况的 metrics,可以通过 Metrics API 获取到, Kubernetes 1.11 已经废弃 heapster.这里我们基于 Kubernet ...