[BZOJ3196][Tyvj1730]二逼平衡树

试题描述

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

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

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

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

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

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

输入

第一行两个数 \(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\) 的后继

输出

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

输入示例

9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5

输出示例

2
4
3
4
9

数据规模及约定

  1. \(n\) 和 \(m\) 的数据范围:\(n,m \le 50000\)

  2. 序列中每个数的数据范围:\([0,10^8]\)

  3. 虽然原题没有,但事实上 \(5\) 操作的 \(k\) 可能为负数

题解

填个坑学了学 fhq treap,感觉挺好写的,还可以轻易地可持久化。就用这个树套树裸题练练手。(下面代码是 \(O(n \log^3 n)\) 的)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--) int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 50010
#define maxnode 2000010
#define oo 2147483647
#define pii pair <int, int>
#define x first
#define y second
#define mp(x, y) make_pair(x, y) int n, A[maxn]; struct Node {
int v, r, siz;
Node() {}
Node(int _): v(_), r(rand()), siz(1) {}
} ns[maxnode];
int ToT, rt[maxn<<2], ch[maxnode][2]; void maintain(int o) {
if(!o) return ;
ns[o].siz = 1;
if(ch[o][0]) ns[o].siz += ns[ch[o][0]].siz;
if(ch[o][1]) ns[o].siz += ns[ch[o][1]].siz;
return ;
}
int merge(int a, int b) {
if(!a) return maintain(b), b;
if(!b) return maintain(a), a;
if(ns[a].r > ns[b].r) return ch[a][1] = merge(ch[a][1], b), maintain(a), a;
return ch[b][0] = merge(a, ch[b][0]), maintain(b), b;
}
pii split(int o, int v) {
if(!o) return mp(0, 0);
pii pr;
if(v <= ns[o].v) {
pr = split(ch[o][0], v);
ch[o][0] = pr.y; maintain(o);
return mp(pr.x, o);
}
pr = split(ch[o][1], v);
ch[o][1] = pr.x; maintain(o);
return mp(o, pr.y);
}
void Insert(int& o, int v) {
pii pr = split(o, v);
ns[++ToT] = Node(v);
o = merge(pr.x, ToT);
o = merge(o, pr.y);
return ;
}
void Delete(int& o, int v) {
if(!o) return ;
if(v == ns[o].v) return (void)(o = merge(ch[o][0], ch[o][1]));
if(v < ns[o].v) Delete(ch[o][0], v);
else Delete(ch[o][1], v);
return maintain(o);
}
int qrnk(int o, int v) {
if(!o) return 0;
int ls = ch[o][0] ? ns[ch[o][0]].siz : 0;
if(v <= ns[o].v) return qrnk(ch[o][0], v);
return ls + 1 + qrnk(ch[o][1], v);
}
int qpre(int o, int v) {
if(!o) return -1;
if(ns[o].v < v) return max(ns[o].v, qpre(ch[o][1], v));
return qpre(ch[o][0], v);
}
int qnxt(int o, int v) {
if(!o) return oo;
if(ns[o].v > v) return min(ns[o].v, qnxt(ch[o][0], v));
return qnxt(ch[o][1], v);
} void build(int o, int l, int r) {
rep(i, l, r) Insert(rt[o], A[i]);
if(l == r) return ;
int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
build(lc, l, mid); build(rc, mid + 1, r);
return ;
}
int modify(int o, int l, int r, int p, int v) {
if(l == r) {
int tmp = ns[rt[o]].v;
Delete(rt[o], tmp);
Insert(rt[o], v);
return tmp;
}
int mid = l + r >> 1, lc = o << 1, rc = lc | 1, tmp;
if(p <= mid) Delete(rt[o], tmp = modify(lc, l, mid, p, v)), Insert(rt[o], v);
else Delete(rt[o], tmp = modify(rc, mid + 1, r, p, v)), Insert(rt[o], v);
return tmp;
}
int qsmaller(int o, int l, int r, int ql, int qr, int v) {
if(ql <= l && r <= qr) return qrnk(rt[o], v);
int mid = l + r >> 1, lc = o << 1, rc = lc | 1, ans = 0;
if(ql <= mid) ans += qsmaller(lc, l, mid, ql, qr, v);
if(qr > mid) ans += qsmaller(rc, mid + 1, r, ql, qr, v);
return ans;
}
int qkth(int ql, int qr, int k) {
int l = 0, r = (int)1e8 + 1;
while(r - l > 1) {
int mid = l + r >> 1;
if(qsmaller(1, 1, n, ql, qr, mid) + 1 <= k) l = mid; else r = mid;
}
return l;
}
int askpre(int o, int l, int r, int ql, int qr, int v) {
if(ql <= l && r <= qr) return qpre(rt[o], v);
int mid = l + r >> 1, lc = o << 1, rc = lc | 1, ans = -1;
if(ql <= mid) ans = max(ans, askpre(lc, l, mid, ql, qr, v));
if(qr > mid) ans = max(ans, askpre(rc, mid + 1, r, ql, qr, v));
return ans;
}
int asknxt(int o, int l, int r, int ql, int qr, int v) {
if(ql <= l && r <= qr) return qnxt(rt[o], v);
int mid = l + r >> 1, lc = o << 1, rc = lc | 1, ans = oo;
if(ql <= mid) ans = min(ans, asknxt(lc, l, mid, ql, qr, v));
if(qr > mid) ans = min(ans, asknxt(rc, mid + 1, r, ql, qr, v));
return ans;
} int main() {
n = read(); int q = read();
rep(i, 1, n) A[i] = read(); build(1, 1, n);
while(q--) {
int tp = read(), l, r, k;
if(tp == 1) l = read(), r = read(), k = read(), printf("%d\n", qsmaller(1, 1, n, l, r, k) + 1);
if(tp == 2) l = read(), r = read(), k = read(), printf("%d\n", qkth(l, r, k));
if(tp == 3) l = read(), k = read(), modify(1, 1, n, l, k);
if(tp == 4) l = read(), r = read(), k = read(), printf("%d\n", askpre(1, 1, n, l, r, k));
if(tp == 5) l = read(), r = read(), k = read(), printf("%d\n", asknxt(1, 1, n, l, r, k));
} return 0;
}

[BZOJ3196][Tyvj1730]二逼平衡树的更多相关文章

  1. BZOJ3196 Tyvj1730 二逼平衡树 【树套树】 【线段树套treap】

    BZOJ3196 Tyvj1730 二逼平衡树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名 ...

  2. [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树

    二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...

  3. bzoj3196 [TYVJ1730]二逼平衡树 树套树 线段树套替罪羊树

    人傻自带大常数 二分的可行性证明: 贴近他的正确答案不会被当作次优解删掉,因为,若二分在他右边发生,那么二分一定会把左边作为优解,左边同理,所以他一定是被扣掉的所以最后一个小于等于一定是正确答案 #i ...

  4. bzoj3196:Tyvj1730二逼平衡树

    传送门 暴力啊,直接树套树上啊 线段树套splay,卡卡常就直接A了 代码: #include<cstdio> #include<iostream> #include<a ...

  5. [BZOJ3196] [Tyvj1730] 二逼平衡树(线段树 套 Splay)

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

  6. 【BZOJ3196】二逼平衡树(树状数组,线段树)

    [BZOJ3196]二逼平衡树(树状数组,线段树) 题面 BZOJ题面 题解 如果不存在区间修改操作: 搞一个权值线段树 区间第K大--->直接在线段树上二分 某个数第几大--->查询一下 ...

  7. [TYVJ1730]二逼平衡树

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

  8. 【BZOJ-3196】二逼平衡树 线段树 + Splay (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2271  Solved: 935[Submit][Stat ...

  9. 【bzoj3196】 Tyvj1730—二逼平衡树

    http://www.lydsy.com/JudgeOnline/problem.php?id=3196 (题目链接) 题意 1.查询k在区间内的排名:2.查询区间内排名为k的值:3.修改某一位值上的 ...

随机推荐

  1. JavaScript -- 继承与原型链

    JavaScript对象有一个指向一个原型对象的链,当试图访问一个对象的属性的时候,他不仅仅会在该对象上面搜寻,还会搜寻该对象的原型,以及对象的原型的原型,依次层层搜索,直到找到名字匹配的属性或者到达 ...

  2. codeblocks编译出错问题的解答!(编译c++ 或者c程序)

    典型错误:https://blog.csdn.net/jingmiaa/article/details/52054204 MinGW下载并配置gcc/g++编译环境:https://blog.csdn ...

  3. BZOJ2693: jzptab(莫比乌斯反演)

    Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2068  Solved: 834[Submit][Status][Discuss] Descripti ...

  4. 关于PHP性能提升踩过的一些坑

        性能这个东西,在网站规模到达一定程度后,会是一个永恒的主题.关于这方面,本人有一些拙见,现在拿出来,大家一起探讨下.     1.编码过程中,传递参数时,尽量少使用‘引用传参’.这是一个巨坑啊 ...

  5. MVC中输入的保护验证用:HttpServerUtility.HtmlEncode

    安全说明: 上面的代码使用HttpServerUtility.HtmlEncode来保护应用程序的恶意输入 (即 JavaScript).详细信息请参阅如何: 在 Web 应用程序,通过应用 HTML ...

  6. oracle 数据被修改怎么修复?(闪回)

    数据被删除 或者 update 的时候忘记勾选where 限制条件,数据全部更新了?  怎么办? 要跑路了? NO !!! 看下面,迅速帮你闪回数据! demo sql: 1. SELECT * FR ...

  7. 单服务器最大tcp连接数及调优汇总

    启动线程数: 启动线程数=[任务执行时间/(任务执行时间-IO等待时间)]*CPU内核数 最佳启动线程数和CPU内核数量成正比,和IO阻塞时间成反比.如果任务都是CPU计算型任务,那么线程数最多不超过 ...

  8. 面试官常问的10个Linux问题

    1.如何暂停一个正在运行的进程,把其放在后台(不运行)? 为了停止正在运行的进程,让其再后台运行,我们可以使用组合键Ctrl+Z. 2.什么是安装Linux所需的最小分区数量,以及如何查看系统启动信息 ...

  9. 【C#】 反射

    [C#] 反射 目录 : http://msdn.microsoft.com/zh-cn/library/System.Reflection(v=vs.110).aspx System.Reflect ...

  10. 给apk签名

    一.签名 把apk和签名文件放在jdk bin目录下,然后在jkd bin目录下执行以下代码: jarsigner -verbose -keystore xxx.keystore -signedjar ...