[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. 解决 Android sdk content loader 0%

    第一次遇到这种情况,真的很头痛,没办法 ,是问题就要解决,在网上找了一些方法,归纳了下来. 方法一(关闭后重启): 遇到Eclipse右下角一直显示“Android sdk content loade ...

  2. JAVAOOP多线程

    进程每个独立运行的任务对应一个进程,每个进程可以产生多个线程 特点:1,进程是系统运行程序的基本单位 2,每一个进程都有自己独立的一块内存空间,一组系统资源 3,每一个进程的内部数据和状态都是完全独立 ...

  3. ZooKeeper异常:Error connecting service It is probably not running

    ZooKeeper安装后使用以下命令可以启动成功 bin/zkServer.sh start 但是使用下面命令查看启动状态,则报错误: bin/zkServer.sh status Error con ...

  4. Python3爬虫(十) 数据存储之非关系型数据库MongoDB

    Infi-chu: http://www.cnblogs.com/Infi-chu/ 一.非关系型数据库NoSQL全程是Not Only SQL,非关系型数据库.NoSQL是基于键值对的,不需要经过S ...

  5. linux中常用命令总结

    一关机/重启/注销 关机 shutdown -h now //立即关机 重启 shutdown -r now //立即重启 reboot 重新启动 注销 logout //退出注销当前用户窗口 exi ...

  6. Android面试收集录 Android系统的资源+其他

    1.Android应用程序的资源是如何存储的,如何使用? res文件夹或者assets文件夹 res目录中的资源在R类中生成一个int变量,然后再布局文件中可以直接使用,在代码中,要getResour ...

  7. 初步学习pg_control文件之二

    接前文:初步认识pg_control文件 继续学习,pg_control文件在何处形成的?是在initdb的时候,运用的函数如下: /* * This func must be called ONCE ...

  8. 10-mongodb启动错误

    1.error信息 python@ubuntu:~$ mongod --22T17:: I CONTROL [initandlisten] MongoDB starting : pid= port= ...

  9. java使用java.util.Properties读取properties文件的九种方法

    直接上代码: package com.test.test; import java.io.BufferedInputStream; import java.io.FileInputStream; im ...

  10. 【数据库】 SQL 常用语句之系统语法

    [数据库] SQL 常用语句之系统语法 1. 获取取数据库服务器上所有数据库的名字 SELECT name FROM master.dbo.sysdatabases 2. 获取取数据库服务器上所有非系 ...