[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. cnpm 下载

    1, 如果电脑已经有node的话,可以先卸载,然后再去node官网下载最新node, 2,先全局安装cnpm, npm install -g cnpm --registry=https://regis ...

  2. PHP中有关IPV4 和IPV6地址转换以及其它一些常见问题

    这里主要介绍一下 IPV4 / IPV6 在 PHP / MySQL 中如何转换.以及中间容易碰到的一些问题. 首先介绍两个函数: ip2long:将 IPV4 的字符串互联网协议转换成长整型数字 i ...

  3. PyCharm+QT Designer整合

    CMD下使用pip安装PyQt4或者PYQT5 这里要注意,你下载的PYQT5不包含QT designer 还要:pip3 install PyQt5-tools,好像Pyqt5中将designer分 ...

  4. MySQL数据表操作(DDL)

    一.创建数据表 语法:create table 表名称(字段 字段类型 [字段属性],字段 字段类型 [字段属性],...) [表选项]; 表选项:数据表的属性,一般包括engine.charset. ...

  5. Java : java基础(3) IO流

    流按操作类型分为两种,字节流,字符流,按流向分为输入流,输出流,输入流的抽象父类InputStream,输出流抽象父类OutputStream,字符流的抽象父类是Reader和Writer 一般用字节 ...

  6. 【Nginx一】Nginx服务器搭建

    Nginx服务器搭建 Nginx服务器搭建 下载Nginx源码包 安装Nginx 解压Nginx安装包 安装Nginx依赖 启动Nginx 下载Nginx源码包 官网下载地址 命令:wget http ...

  7. 【ajax】ajax异步实现用户注册验证

    从前台到后台实现简单用户注册检查用户是否存在 1.编写domain public class User { private String username; private String passwo ...

  8. C++ 指针初始化要注意的地方

    1. 声明多个指针的时候: int* P1,P2; 如上所示,声明的是创建一个指针P1和一个int型的变量P2.而不是声明的两个指针. 对每个指针变量名,都需要使用一个*. 在C++中,int* 是一 ...

  9. 洛谷P4016 负载平衡问题

    题目描述 G 公司有 n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 n 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入输出格式 输入格式: ...

  10. 販売管理(SD)

    SD(販売管理)系のSAP DBテーブル. 随時更新していきます. [得意先マスタ]KNA1: 一般データ KNB1: 会計データ KNBK: 銀行データ KNVV: 販売データ KNVP: 取引先機 ...