题目

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

1.查询k在区间内的排名

2.查询区间内排名为k的值

3.修改某一位值上的数值

4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)

5.查询k在区间内的后继(后继定义为大于x,且最小的数)

Input

第一行两个数 n,m 表示长度为n的有序序列和m个操作

第二行有n个数,表示有序序列

下面有m行,opt表示操作标号

若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名

若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数

若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k

若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱

若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

Output

对于操作1,2,4,5各输出一行,表示查询结果

题解

树套树模板题。

对于每一个线段树上的节点,我们都在上面建一个平衡树。

对于操作1,我们把一个长度为len的区间分解为\(\lfloor log_2(len) \rfloor\)个子区间,分别处理,把每个区间的排名加起来就好了。

对于操作2,我们二分答案,对于二分出来的一个答案执行操作1,check以下即可。

对于操作3,我们删除再插入。

对于操作4和操作5,我们把每个区间(前驱/后继)的(最大值/最小值)搞一搞就好啦。

PS.谁能告诉我bzoj上那些2000ms的是怎么做的。。。

代码

#include <algorithm>
#include <cctype>
#include <cstdio>
using namespace std;
const int maxn = 4e6 + 5;
const int inf = 1e9;
int ans, n, m, opt, l, r, k, pos, sz, Max;
int a[maxn], fa[maxn], ch[maxn][2], size[maxn], cnt[maxn], data[maxn], rt[maxn];
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
struct Splay {
void clear(int x) {
fa[x] = ch[x][0] = ch[x][1] = size[x] = cnt[x] = data[x] = 0;
}
void update(int x) {
if (x) {
size[x] = cnt[x];
if (ch[x][0])
size[x] += size[ch[x][0]];
if (ch[x][1])
size[x] += size[ch[x][1]];
}
}
void zig(int x) {
int y = fa[x], z = fa[y], l = (ch[y][1] == x), r = l ^ 1;
fa[ch[y][l] = ch[x][r]] = y;
fa[ch[x][r] = y] = x;
fa[x] = z;
if (z)
ch[z][ch[z][1] == y] = x;
update(y);
update(x);
}
void splay(int i, int x, int aim = 0) {
for (int y; (y = fa[x]) != aim; zig(x))
if (fa[y] != aim)
zig((ch[fa[y]][0] == y) == (ch[y][0] == x) ? y : x);
if (aim == 0)
rt[i] = x;
}
void insert(int i, int v) {
int x = rt[i], y = 0;
if (x == 0) {
rt[i] = x = ++sz;
fa[x] = ch[x][0] = ch[x][1] = 0;
size[x] = cnt[x] = 1;
data[x] = v;
return;
}
while (1) {
if (data[x] == v) {
cnt[x]++;
update(y);
splay(i, x);
return;
}
y = x;
x = ch[x][v > data[x]];
if (x == 0) {
++sz;
fa[sz] = y;
ch[sz][0] = ch[sz][1] = 0;
size[sz] = cnt[sz] = 1;
data[sz] = v;
ch[y][v > data[y]] = sz;
update(y);
splay(i, sz);
rt[i] = sz;
return;
}
}
}
void find(int i, int v) {
int x = rt[i];
while (1) {
if (data[x] == v) {
splay(i, x);
return;
} else
x = ch[x][v > data[x]];
}
}
int pre(int i) {
int x = ch[rt[i]][0];
while (ch[x][1])
x = ch[x][1];
return x;
}
int succ(int i) {
int x = ch[rt[i]][1];
while (ch[x][0])
x = ch[x][0];
return x;
}
void del(int i) {
int x = rt[i];
if (cnt[x] > 1) {
cnt[x]--;
return;
}
if (!ch[x][0] && !ch[x][1]) {
clear(rt[i]);
rt[i] = 0;
return;
}
if (!ch[x][0]) {
int oldroot = x;
rt[i] = ch[x][1];
fa[rt[i]] = 0;
clear(oldroot);
return;
}
if (!ch[x][1]) {
int oldroot = x;
rt[i] = ch[x][0];
fa[rt[i]] = 0;
clear(oldroot);
return;
}
int y = pre(i), oldroot = x;
splay(i, y);
rt[i] = y;
ch[rt[i]][1] = ch[oldroot][1];
fa[ch[oldroot][1]] = rt[i];
clear(oldroot);
update(rt[i]);
return;
}
int rank(int i, int v) {
int x = rt[i], ans = 0;
while (1) {
if (!x)
return ans;
if (data[x] == v)
return ((ch[x][0]) ? size[ch[x][0]] : 0) + ans;
else if (data[x] < v) {
ans += ((ch[x][0]) ? size[ch[x][0]] : 0) + cnt[x];
x = ch[x][1];
} else if (data[x] > v) {
x = ch[x][0];
}
}
}
int find_pre(int i, int v) {
int x = rt[i];
while (x) {
if (data[x] < v) {
if (ans < data[x])
ans = data[x];
x = ch[x][1];
} else
x = ch[x][0];
}
return ans;
}
int find_succ(int i, int v) {
int x = rt[i];
while (x) {
if (v < data[x]) {
if (ans > data[x])
ans = data[x];
x = ch[x][0];
} else
x = ch[x][1];
}
return ans;
}
} sp;
void insert(int k, int l, int r, int x, int v) {
int mid = (l + r) >> 1;
sp.insert(k, v);
if (l == r)
return;
if (x <= mid)
insert(k << 1, l, mid, x, v);
else
insert(k << 1 | 1, mid + 1, r, x, v);
}
void askrank(int k, int l, int r, int x, int y, int val) {
int mid = (l + r) >> 1;
if (x <= l && r <= y) {
ans += sp.rank(k, val);
return;
}
if (x <= mid)
askrank(k << 1, l, mid, x, y, val);
if (mid + 1 <= y)
askrank(k << 1 | 1, mid + 1, r, x, y, val);
}
void change(int k, int l, int r, int pos, int val) {
int mid = (l + r) >> 1;
sp.find(k, a[pos]);
sp.del(k);
sp.insert(k, val);
if (l == r)
return;
if (pos <= mid)
change(k << 1, l, mid, pos, val);
else
change(k << 1 | 1, mid + 1, r, pos, val);
}
void askpre(int k, int l, int r, int x, int y, int val) {
int mid = (l + r) >> 1;
if (x <= l && r <= y) {
ans = max(ans, sp.find_pre(k, val));
return;
}
if (x <= mid)
askpre(k << 1, l, mid, x, y, val);
if (mid + 1 <= y)
askpre(k << 1 | 1, mid + 1, r, x, y, val);
}
void asksucc(int k, int l, int r, int x, int y, int val) {
int mid = (l + r) >> 1;
if (x <= l && r <= y) {
ans = min(ans, sp.find_succ(k, val));
return;
}
if (x <= mid)
asksucc(k << 1, l, mid, x, y, val);
if (mid + 1 <= y)
asksucc(k << 1 | 1, mid + 1, r, x, y, val);
}
int main() {
#ifdef D
freopen("input", "r", stdin);
#endif
n = read(), m = read();
for (int i = 1; i <= n; i++)
a[i] = read(), Max = max(Max, a[i]), insert(1, 1, n, i, a[i]);
for (int i = 1; i <= m; i++) {
opt = read();
if (opt == 1) {
l = read(), r = read(), k = read();
ans = 0;
askrank(1, 1, n, l, r, k);
printf("%d\n", ans + 1);
} else if (opt == 2) {
l = read(), r = read(), k = read();
int head = 0, tail = Max + 1;
while (head != tail) {
int mid = (head + tail) >> 1;
ans = 0;
askrank(1, 1, n, l, r, mid);
if (ans < k)
head = mid + 1;
else
tail = mid;
}
printf("%d\n", head - 1);
} else if (opt == 3) {
pos = read();
k = read();
change(1, 1, n, pos, k);
a[pos] = k;
Max = std::max(Max, k);
} else if (opt == 4) {
l = read();
r = read();
k = read();
ans = 0;
askpre(1, 1, n, l, r, k);
printf("%d\n", ans);
} else if (opt == 5) {
l = read();
r = read();
k = read();
ans = inf;
asksucc(1, 1, n, l, r, k);
printf("%d\n", ans);
}
}
}

[bzoj3196]Tyvj 1730 二逼平衡树——线段树套平衡树的更多相关文章

  1. bzoj3196: Tyvj 1730 二逼平衡树 树套树

    地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3196 题目: 3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec ...

  2. BZOJ3196二逼平衡树——线段树套平衡树(treap)

    此为平衡树系列最后一道:二逼平衡树您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询 ...

  3. 【线段树套平衡树】【pb_ds】bzoj3196 Tyvj 1730 二逼平衡树

    线段树套pb_ds里的平衡树,在洛谷OJ上测试,后三个测试点TLE #include<cstdio> #include<algorithm> #include<ext/p ...

  4. BZOJ3196: Tyvj 1730 二逼平衡树

    传送门 主席树的常数蜜汁优越,在BZOJ上跑了rnk1. 做法很简单,主席树套BIT. 1-3做法很简单,第四个和第五个做法转换成前两个就行了. //BZOJ 3196 //by Cydiater / ...

  5. 【分块】bzoj3196 Tyvj 1730 二逼平衡树

    分块 或 树套树. 在每个块中维护一个有序表,查询时各种二分,全都是分块的经典操作,就不详细说了. 块的大小定为sqrt(n*log2(n))比较快. #include<cstdio> # ...

  6. bzoj3196 二逼平衡树——线段树套平衡树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3196 人生中第一棵树套树! 写了一个晚上,成功卡时 9000ms+ 过了! 很要注意数组的大 ...

  7. bzoj 3196二逼平衡树 线段树套平衡树

    比较裸的树套树,对于区间K值bz上有一道裸题,详见题解http://www.cnblogs.com/BLADEVIL/p/3455336.html(其实题解也不是很详细) //By BLADEVIL ...

  8. [bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

    Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在 ...

  9. 【带修莫队】【权值分块】bzoj3196 Tyvj 1730 二逼平衡树

    这题用了三种算法写: 分块+二分:O(n*sqrt(n*log(n)) 函数式权值分块:O(n*sqrt(n)) 带修莫队+权值分块:O(n5/3) 结果……复杂度越高的实际上跑得越快……最后这个竟然 ...

随机推荐

  1. C# 存储过程使用方法

                CREATE PROCEDURE [dbo].[GetNameById] @studentid varchar(8), @studentname nvarchar(50) OU ...

  2. 神经网络NN

    神经网络基本模型: 1.前向神经网络:无圈的有向图N=(V,E,W),其中,V为神经元集合,E为连结权值集合,W为每一连结赋予一实值的权重. 神经元集V可以被分成无接受域的输入结点集V1,无投射域的输 ...

  3. 超炫的时间轴jquery插件Timeline Portfolio

    Timeline Portfolio是一款按时间顺序专业显示事件的jquery时间轴插件,可以根据时间的先后嵌入各种媒体包括微博,视频和地图等.这个展现的模式非常适合设计师的作品集和个人简历的展示.T ...

  4. [ Android 五种数据存储方式之四 ] —— ContentProvider存储数据

    Android这个系统和其他的操作系统还不太一样,我们需要记住的是,数据在Android当中是私有的,当然这些数据包括文件数据和数据库数据以及一些其他类型的数据.那这个时候有读者就会提出问题,难道两个 ...

  5. KingbaseES的standby搭建

    KingbaseES数据库部署及双机热备配置 Dataguard双机热备部署 注:配置期间使用数据库的属主用户进行操作 1.1 数据一致性准备 (1)修改数据库的配置文件参数:(2阶段初始化的数据库实 ...

  6. 部署statspack工具(二)之解决方案1

    7.解决方案一:调整buffer cache sys@TESTDB12>alter system set sga_max_size=804m scope=spfile;        //重启数 ...

  7. Tomcat 使用过程中的一些技巧

    url中文地址乱码 原因: tomcat默认的在url传输时是用iso8859-1编码. 解决方案一: 在使用get传输参数时,将参数中的中文转换成url格式,也就是使用urlEncode和urlDe ...

  8. POJ2796(单调栈)

    Feel Good Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12987   Accepted: 3639 Case T ...

  9. C++ Primer 笔记 第一章

    C++ Primer 学习笔记 第一章 快速入门 1.1 main函数 系统通过调用main函数来执行程序,并通过main函数的返回值确定程序是否成功执行完毕.通常返回0值表明程序成功执行完毕: ma ...

  10. ArcGIS制图技巧系列(3)—让地图更有立体感

    ArcGIS制图技巧系列(3)-让地图更有立体感 by 李远祥 在前面的章节中,我们已经介绍过各种的地图效果,如发光效果,山体阴影效果,植被填充效果等,所有的这些效果不外乎是各种技术的叠加和技巧的使用 ...