\(\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. vue render中如何正确配置img的路径

    第一种:适用于静态路径 attrs: { src: require('../common/images/logo.png'), title: 'img' } 第二种:适用于动态路径 domProps: ...

  2. springboot启动过程中常用的回调

    1.介绍 springboot提供非常丰富回调接口,利用这些接口可以做非常多的事情,对于一些常用的回调接口进行介绍 2.常用的拓展接口 1.ApplicationContextInitializer ...

  3. 构造注入链:POP

    1.POP链原理简介: 在反序列化中,我们能控制的数据就是对象中的属性值,所以在PHP反序列化中有一种 漏洞利用方法叫"面向属性编程",即POP( Property Oriente ...

  4. 深入理解Java虚拟机之Java内存区域与内存溢出异常

    Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...

  5. Springboot集成邮箱服务发送邮件

    一.前言 Spring Email 抽象的核心是 MailSender 接口,MailSender 的实现能够把 Email 发送给邮件服务器,由邮件服务器实现邮件发送的功能. Spring 自带了一 ...

  6. css3中transition属性详解

    css3中通过transition属性可以实现一些简单的动画过渡效果~ 1.语法 transition: property duration timing-function delay; transi ...

  7. 《剑指offer》面试题28. 对称的二叉树

    问题描述 请实现一个函数,用来判断一棵二叉树是不是对称的.如果一棵二叉树和它的镜像一样,那么它是对称的. 例如,二叉树 [1,2,2,3,4,4,3] 是对称的.     1    / \   2   ...

  8. JavaScript创建和获取时间的方法

    一.获取时间常用方法 1.创建时间对象 var time=new Date() //创建当前的时间信息对象 var time1=new Date(2022,1,1,10,25,30) //创建2022 ...

  9. manjaro20夜灯夜间模式开关

  10. node.js在Linux下执行shell命令、.sh脚本

    首先,引入子进程模块 var process = require('child_process'); 执行shell命令 调用该模块暴露出来的方法exec process.exec('shutdown ...