【BZOJ3196】【Luogu P3380】 【模板】二逼平衡树(树套树)
做数据结构一定要平\((fo)\)心\((de)\)静\((yi)\)气\((pi)\)。。。不然会四处出锅的\(QAQ\)
写法:线段树套平衡树,\(O(Nlog^3N)\)。五个操作如果是对于整个区间的,那么就是平衡树板子题。现在既然是放在子区间上的,那么套一个线段树就好啦~
#include <bits/stdc++.h>
using namespace std;
const int N = 50000 + 5;
const int INF = 1e8 + 5;
#define ls (p << 1)
#define rs (p << 1 | 1)
#define mid ((l + r) >> 1)
int n, m, tot, arr[N];
struct FHQ_Node {
int w, lc, rc, sz, rd;
}t[N << 8];
struct FHQ_Treap {
int rt;
int NewNode (int w) {
t[++tot] = FHQ_Node {w, 0, 0, 1, rand ()};
return tot;
}
void push_up (int p) {
t[p].sz = 1;
if (t[p].lc) t[p].sz += t[t[p].lc].sz;
if (t[p].rc) t[p].sz += t[t[p].rc].sz;
}
void split (int now, int &A, int &B, int w) {
if (now == 0) {
A = B = 0; return;
}
if (t[now].w <= w) {
A = now; split (t[now].rc, t[A].rc, B, w);
} else {
B = now; split (t[now].lc, A, t[B].lc, w);
}
push_up (now);
}
int merge (int A, int B) {
if (A * B == 0) {
return A + B;
}
if (t[A].rd < t[B].rd) {
t[A].rc = merge (t[A].rc, B);
push_up (A); return A;
} else {
t[B].lc = merge (A, t[B].lc);
push_up (B); return B;
}
}
int x, y, z;
void Insert (int w) {
split (rt, x, y, w);
rt = merge (x, merge (NewNode (w), y));
// cout << "rt = " << rt << endl;
}
void Delete (int w) {
split (rt, x, y, w - 1);
split (y, y, z, w);
y = merge (t[y].lc, t[y].rc);
rt = merge (x, merge (y, z));
}
int pre (int w) {
split (rt, x, y, w - 1);
int p = x;
if (p == 0) {
return -0x7fffffff;
}
while (t[p].rc != 0) {
p = t[p].rc;
}
rt = merge (x, y);
return t[p].w;
}
int nxt (int w) {
split (rt, x, y, w);
int p = y;
if (p == 0) {
return +0x7fffffff;
}
while (t[p].lc != 0) {
p = t[p].lc;
}
rt = merge (x, y);
return t[p].w;
}
void print (int p) {
if (t[p].lc) print (t[p].lc);
// cout << "p = " << p << " w = " << t[p].w << " sz = " << t[p].sz << endl;
if (t[p].rc) print (t[p].rc);
}
int rank (int w) {
split (rt, x, y, w - 1);
int ret = t[x].sz + 1;
rt = merge (x, y);
// print (rt); cout << endl;
return ret;
}
};
struct Segment_Tree {
FHQ_Treap tree[N << 2];
void modify (int pos, int wpre, int wnew, int l = 1, int r = n, int p = 1) {
// cout << "p = " << p << endl;
if (wpre != -1) {tree[p].Delete (wpre);/*cout << "tree[" << p << "].Delete (" << wpre << ");" << endl;*/}
if (wnew != -1) {tree[p].Insert (wnew);/*cout << "tree[" << p << "].Insert (" << wnew << ");" << endl;*/}
if (l == r) return;
if (pos <= mid) {
modify (pos, wpre, wnew, l, mid + 0, ls);
} else {
modify (pos, wpre, wnew, mid + 1, r, rs);
}
}
int tot, sta[N];
void get_segment (int nl, int nr, int l = 1, int r = n, int p = 1) {
if (p == 1) tot = 0;
if (nl <= l && r <= nr) {
sta[++tot] = p; return;
}
if (nl <= mid) get_segment (nl, nr, l, mid + 0, ls);
if (mid < nr) get_segment (nl, nr, mid + 1, r, rs);
}
int rank (int l, int r, int w) {
get_segment (l, r);
int ret = 1;
for (int i = 1; i <= tot; ++i) {
// cout << tree[sta[i]].rank (w) << endl;
ret += (tree[sta[i]].rank (w) - 1);
}
// cout << "val = " << w << " rank = " << ret << endl;
return ret;
}
int kth (int l, int r, int k) {
int lval = 0, rval = INF;
// cout << "k = " << k << endl;
while (lval < rval) {
// getchar ();
int _mid = (lval + rval + 1) >> 1;
// cout << "lval = " << lval << " rval = " << rval << " mid = " << _mid << " rank " << k << " = " << rank (l, r, _mid) << endl;
if (rank (l, r, _mid) <= k) {
lval = _mid;
} else {
rval = _mid - 1;
}
}
return lval;
}
int pre (int l, int r, int w) {
get_segment (l, r);
int maxw = -0x7fffffff;
for (int i = 1; i <= tot; ++i) {
maxw = max (maxw, tree[sta[i]].pre (w));
}
return maxw;
}
int nxt (int l, int r, int w) {
get_segment (l, r);
int minw = +0x7fffffff;
for (int i = 1; i <= tot; ++i) {
minw = min (minw, tree[sta[i]].nxt (w));
}
return minw;
}
}tr;
int read () {
int s = 0, ch = getchar ();
while (!isdigit (ch)) {
ch = getchar ();
}
while (isdigit (ch)) {
s = s * 10 + ch - '0';
ch = getchar ();
}
return s;
}
int main () {
// freopen ("data.in", "r", stdin);
srand (time (NULL));
n = read (), m = read ();
for (int i = 1; i <= n; ++i) {
int w = read ();
tr.modify (i, -1, w);
arr[i] = w;
// cout << endl;
}
int opt, pos, l, r, k;
for (int i = 1; i <= m; ++i) {
opt = read ();
if (opt == 1) {
l = read (), r = read (), k = read ();
cout << tr.rank (l, r, k) << endl;
}
if (opt == 2) {
l = read (), r = read (), k = read ();
cout << tr.kth (l, r, k) << endl;
}
if (opt == 3) {
pos = read (), k = read ();
tr.modify (pos, arr[pos], k);
arr[pos] = k;
}
if (opt == 4) {
l = read (), r = read (), k = read ();
cout << tr.pre (l, r, k) << endl;
}
if (opt == 5) {
l = read (), r = read (), k = read ();
cout << tr.nxt (l, r, k) << endl;
}
}
}
【BZOJ3196】【Luogu P3380】 【模板】二逼平衡树(树套树)的更多相关文章
- 【bzoj3196】Tyvj 1730 二逼平衡树 线段树套Treap
题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义 ...
- bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1807 Solved: 772[Submit][Stat ...
- bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description ...
- 【BZOJ3196】Tyvj 1730 二逼平衡树
Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的 ...
- BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)
我实在是不想再打一遍树状数组套替罪羊树了... 然后在普通平衡树瞎逛的时候找到了以前看过vector题解 于是我想:为啥不把平衡树换成vector呢??? 然后我又去学了一下ZKW线段树 就用ZKW线 ...
- BZOJ3196 二逼平衡树 【线段树套平衡树】
题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱 ...
- BZOJ 3196 Tyvj 1730 二逼平衡树:线段树套splay
传送门 题意 给你一个长度为 $ n $ 有序数列 $ a $ ,进行 $ m $ 次操作,操作有如下几种: 查询 $ k $ 在区间 $ [l,r] $ 内的排名 查询区间 $ [l,r] $ 内排 ...
- [BZOJ3196] [Tyvj1730] 二逼平衡树(线段树 套 Splay)
传送门 至少BZOJ过了,其他的直接弃. 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的 ...
- bzoj 3196 Tyvj 1730 二逼平衡树【线段树 套 splay】
四舍五入就是个暴力. 对于线段树的每个区间都开一棵按权值排序的splay 对于第二个操作,二分一下,每次查询mid的排名,复杂度 $ O(nlog(n)^{3}) $ 其余的操作都是$ O(nlog( ...
- 洛谷 P3380 bzoj3196 Tyvj1730 【模板】二逼平衡树(树套树)
[模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数值 查询k在 ...
随机推荐
- spark map和mapPartitions的区别
package dayo1 import org.apache.spark.{SparkConf, SparkContext} import scala.collection.mutable.Arra ...
- Java并发编程之程序运行堆栈分析
Java程序运行的堆栈分析 1.JVM运行时数据区 JVM通过加载class文件的数据来执行程序.JVM在运行时会划分不同的区域以存放数据.如下图所示: 线程共享部分:所有线程都能访问这块内存的数据, ...
- 关于SQL关键字"having "
HAVING 子句 在 SQL 中增加 HAVING 子句原因是,WHERE 关键字无法与合计函数一起使用. SQL HAVING 语法 SELECT column_name, aggregate_f ...
- 什么是java的线程安全?同步,异步
线程是比进程更小的执行单位,是在进程基础上进行的进一步划分.所谓多线程是指进程在执行过程中可以产生多个同时存在.同时运行的线程.多进程机制可以合理利用资源,提高程序的运行效率.一个进程至少包含一个线程 ...
- Python 输入IP地址及掩码告诉你该网段包含的全部地址(IPy模块练习)
IPy模块原本使用时需要输入正确的网络位和掩码,我利用处理报错的机制实现了输入任意IP地址和掩码均可正确输出结果的小程序. #!/usr/bin/env python # -*- coding: ut ...
- 小记---------sparkRDD的Transformation 和 Action 及案例 原理解释
RDD :弹性分布式数据集:是一个容错的.并行的数据结构,可以让用户显式地将数据存储到磁盘或内存中,并控制数据的分区 RDD是Spark的核心数据结构,通过RDD的依赖关系形成Spark的调度顺序 ...
- python_0基础开始_day10
第十节 一.函数进阶 动态参数 *a r g s —— 聚合位置参数,动态位置参数 默认返回的是tuple元组 def eat(*args): # 函数的定义阶段 *聚合(打包) print( ...
- 如何用纯 CSS 创作出平滑的层叠海浪特效
效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/JvmBdE 可交互视频教 ...
- 如何用纯 CSS 创作一个菜单反色填充特效
效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览.https://codepen.io/comehope/pen/qYMoPo 可交互视频教程 ...
- 分布式的几件小事(五)dubbo的spi思想是什么
1.什么是SPI机制 SPI 全称为 Service Provider Interface,是一种服务发现机制. SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实 ...