[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. vue组件的基本知识点

    1. 组件中 is 的特性: 有些 HTML 元素,诸如 <ul>.<ol>.<table> 和 <select>,对于哪些元素可以出现在其内部是有严格 ...

  2. echarts重新加载动画

    echarts重新加载动画 var option1 = area_right_top1.getOption();area_right_top1.clear();area_right_top1.setO ...

  3. 【cisco下针对冗余链路故障备份的处理措施】

    对于中小型的网络中,为了流量的分担,可制定负载均衡方案,但往往带来的是链路的冗余.导致多条物理线路不能够最大的发挥其作用:冗余链路随可避免环路,但在实际的网络中还是存在一些需要完善的地方: 假设有一组 ...

  4. web pack

    WebPack是模块捆绑器,如果你的代码跨越了不同模块(例如不同Javascript文件),web pack可以将这些零散的代码构建到浏览器可读单个文件中. web pack还可以作为构建通道,你可以 ...

  5. mysql更新返回值问题(更新内容跟之前内容一样,返回0)

    mysql更新返回值问题 问: 有一界面要更新个人信息,有几十个text标签需要填写假设有一用户从用户列表点修改进入了修改页面,但又没有修改什么,马上点击保存这时,因为text标签非常多,不能够一一判 ...

  6. python学习——函数

     一.在python的世界里什么是函数: 答:函数通常是用来实现某一个功能二被封装成的一个对象,是用来实现代码复用的常用方式 现在有一个需求,假如你在不知道len()方法的情况下,要你计算字符串‘he ...

  7. scrapy框架爬取笔趣阁

    笔趣阁是很好爬的网站了,这里简单爬取了全部小说链接和每本的全部章节链接,还想爬取章节内容在biquge.py里在加一个爬取循环,在pipelines.py添加保存函数即可 1 创建一个scrapy项目 ...

  8. [转]Makefile中使用$$的使用

    在makefile中,会经常使用shell命令,也经常见到$var 和 $$var的情况,有什么区别呢,区别大了.不要认为在makefile的规则的命令行中使用$var就是将makefile的变量和s ...

  9. WPF中,如何将绑定源设置到单件实例

    原文:WPF中,如何将绑定源设置到单件实例  WPF中,如何将绑定源设置到单件实例                                       周银辉 大概两个月前,曾有位朋友问我:如 ...

  10. C# Winform 实现屏蔽键盘的win和alt+F4的实现代码

    最近在做一个恶搞程序,就是打开后,程序获得桌面的截图然后,然后全屏显示在屏幕上,用户此时则不能进行任何操作. 此时希望用户不能通过键盘alt+F4来结束程序及通过Win的组合键对窗口进行操作.我在网上 ...