\(\color{#0066ff}{ 题目描述 }\)

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

  1. 查询k在区间内的排名
  2. 查询区间内排名为k的值
  3. 修改某一位值上的数值
  4. 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)
  5. 查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)

\(\color{#0066ff}{输入格式}\)

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

\(\color{#0066ff}{输出格式}\)

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

\(\color{#0066ff}{输入样例}\)

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

\(\color{#0066ff}{输出样例}\)

2
4
3
4
9

\(\color{#0066ff}{数据范围与提示}\)

时空限制:2s,128M

\(n,m \leq 5\cdot {10}^4\)保证有序序列所有值在任何时刻满足 \([0, {10} ^8]\)

\(\color{#0066ff}{ 题解 }\)

可以线段树套平衡树

对于操作1,线段树每个区间在平衡树上找比k小的数的个数,加起来再加1就是排名

对于操作2,可以二分答案,然后通过操作1来判断\(O(log^3n)\)

对于操作3,相当于删除再插入,注意线段树整个一条链都要改

对于操作4,5,线段树子区间答案取max和min即可

#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int maxn = 5e4 + 10;
const int inf = 0x7fffffff;
struct Splay {
protected:
struct node {
node *ch[2], *fa;
int val, siz;
node(node *fa = NULL, int val = 0, int siz = 0): fa(fa), val(val), siz(siz) { ch[0] = ch[1] = NULL; }
void upd() { siz = (ch[0]? ch[0]->siz : 0) + (ch[1]? ch[1]->siz : 0) + 1; }
bool isr() { return this == fa->ch[1]; }
int rk() { return ch[0]? ch[0]->siz + 1 : 1; }
}*root;
void rot(node *x) {
node *y = x->fa, *z = y->fa;
bool k = x->isr(); node *w = x->ch[!k];
if(y != root) z->ch[y->isr()] = x;
else root = x;
x->ch[!k] = y, y->ch[k] = w;
y->fa = x, x->fa = z;
if(w) w->fa = y;
y->upd(), x->upd();
}
void splay(node *o) {
while(o != root) {
if(o->fa != root) rot(o->isr() ^ o->fa->isr()? o : o->fa);
rot(o);
}
}
node *merge(node *x, node *y, node *fa) {
if(x) x->fa = fa;
if(y) y->fa = fa;
if(!x || !y) return x? x : y;
if(rand() & 1) return x->ch[1] = merge(x->ch[1], y, x), x->upd(), x;
else return y->ch[0] = merge(x, y->ch[0], y), y->upd(), y;
}
public:
int rnk(int val) {
node *o = root, *lst = root; int rank = 0;
while(o) {
lst = o;
if(val > o->val) rank += o->rk(), o = o->ch[1];
else o = o->ch[0];
}
return splay(lst), rank;
}
int kth(int k) {
node *o = root;
while(o->rk() != k) {
if(k > o->rk()) k -= o->rk(), o = o->ch[1];
else o = o->ch[0];
}
return splay(o), o->val;
}
int pre(int val) {
node *o = root, *lst = root;
while(o) {
if(o->val < val) lst = o, o = o->ch[1];
else o = o->ch[0];
}
return splay(lst), lst->val;
}
int nxt(int val) {
node *o = root, *lst = root;
while(o) {
if(o->val > val) lst = o, o = o->ch[0];
else o = o->ch[1];
}
return splay(lst), lst->val;
}
void ins(int val) {
if(!root) return (void)(root = new node(NULL, val, 1));
node *o = root, *fa = NULL;
while(o) fa = o, o = o->ch[val > o->val];
fa->ch[val > fa->val] = o = new node(fa, val, 1);
splay(o);
}
void del(int val) {
node *o = root;
while(o->val != val) o = o->ch[val > o->val];
if(!o) return;
splay(o);
root = merge(o->ch[0], o->ch[1], NULL);
delete o;
}
};
struct SGT {
private:
struct node {
int l, r;
node *ch[2];
Splay *s;
node(int l = 0, int r = 0, Splay *s = NULL): l(l), r(r), s(s) { ch[0] = ch[1] = NULL; }
}*root;
void build(node *&o, int l, int r, int *a) {
o = new node(l, r, new Splay());
for(int i = l; i <= r; i++) o->s->ins(a[i]);
if(l == r) return;
int mid = (l + r) >> 1;
build(o->ch[0], l, mid, a), build(o->ch[1], mid + 1, r, a);
}
int rnk(node *o, int l, int r, int val) {
if(o->r < l || o->l > r) return 0;
if(l <= o->l && o->r <= r) return o->s->rnk(val);
return rnk(o->ch[0], l, r, val) + rnk(o->ch[1], l, r, val);
}
int pre(node *o, int l, int r, int val) {
if(o->r < l || o->l > r) return inf;
if(l <= o->l && o->r <= r) return o->s->pre(val);
int ans = -inf;
int L = pre(o->ch[0], l, r, val);
int R = pre(o->ch[1], l, r, val);
if(L < val) ans = std::max(ans, L);
if(R < val) ans = std::max(ans, R);
return ans;
}
int nxt(node *o, int l, int r, int val) {
if(o->r < l || o->l > r) return -inf;
if(l <= o->l && o->r <= r) return o->s->nxt(val);
int ans = inf;
int L = nxt(o->ch[0], l, r, val);
int R = nxt(o->ch[1], l, r, val);
if(L > val) ans = std::min(ans, L);
if(R > val) ans = std::min(ans, R);
return ans;
}
void change(node *o, int pos, int val, int old) {
if(o->r < pos || o->l > pos) return;
o->s->del(old);
o->s->ins(val);
if(o->l == o->r) return;
change(o->ch[0], pos, val, old);
change(o->ch[1], pos, val, old);
}
public:
void build(int *a, int l, int r) { build(root, l, r, a); }
int rnk(int val, int l, int r) { return rnk(root, l, r, val) + 1; }
int kth(int k, int L, int R) {
int l = 0, r = 1e8, ans = 0;
while(l <= r) {
int mid = (l + r) >> 1;
if(rnk(mid, L, R) <= k) ans = mid, l = mid + 1;
else r = mid - 1;
}
return ans;
}
void change(int pos, int old, int now) { change(root, pos, now, old); }
int pre(int val, int l, int r) { return pre(root, l, r, val); }
int nxt(int val, int l, int r) { return nxt(root, l, r, val); }
}v;
int a[maxn];
int main() {
int p, l, r, k, n = in(), m = in();
for(int i = 1; i <= n; i++) a[i] = in();
v.build(a, 1, n);
while(m --> 0) {
p = in();
if(p == 1) l = in(), r = in(), k = in(), printf("%d\n", v.rnk(k, l, r));
if(p == 2) l = in(), r = in(), k = in(), printf("%d\n", v.kth(k, l, r));
if(p == 3) l = in(), k = in(), v.change(l, a[l], k), a[l] = k;
if(p == 4) l = in(), r = in(), k = in(), printf("%d\n", v.pre(k, l, r));
if(p == 5) l = in(), r = in(), k = in(), printf("%d\n", v.nxt(k, l, r));
}
return 0;
}

P3380 【模板】二逼平衡树(树套树) 线段树套平衡树的更多相关文章

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

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

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

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

  3. 洛谷 P3919 【模板】可持久化数组(可持久化线段树/平衡树)-可持久化线段树(单点更新,单点查询)

    P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目背景 UPDATE : 最后一个点时间空间已经放大 标题即题意 有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集 ...

  4. [BZOJ1146][CTSC2008]网络管理Network(二分+树链剖分+线段树套平衡树)

    题意:树上单点修改,询问链上k大值. 思路: 1.DFS序+树状数组套主席树 首先按照套路,关于k大值的问题,肯定要上主席树,每个点维护一棵权值线段树记录它到根的信息. 关于询问,就是Que(u)+Q ...

  5. BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

    题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...

  6. BZOJ 3218(a + b Problem-二分图套值域线段树)

    出这题的人是怎么想出来的…… 言归正传,这题是二分图套值域线段树. 首先经过 @Vfleaking的神奇建图后,把图拆成二分图, 不妨利用有向图最小割的性质建图(以前我一直以为最小割和边的方向无关,可 ...

  7. 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)

    线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...

  8. 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)

    模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...

  9. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  10. hdu 1166:敌兵布阵(树状数组 / 线段树,入门练习题)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

随机推荐

  1. java集合类(2)

    java集合的主要分为三种类型:JAVA集合位于 java.util包 Set(集) List(列表) Map(映射) arrays函数, equals():比较两个array是否相等. fill() ...

  2. DAY12-前端之HTML

    一.html初识 web服务本质 import socket def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ...

  3. 解决html中的乱码问题

    1.最简单粗暴的方法就是加一个meta标签,不过值得我们注意的是我们的meta标签是与我们的head标签是同一级的,所以千万不能将meta标签加到我们的head标签中. <meta http-e ...

  4. TabHost两种不同的实现方式

    第一种:继承TabActivity,从TabActivity中用getTabHost()方法获取TabHost.只要定义具体Tab内容布局就行了 第二种:不用继承TabActivity,在布局文件中定 ...

  5. [codevs1159]最大全0子矩阵(悬线法)

    解题关键:悬线法模板题.注意此模板用到了滚动数组. #include<cstdio> #include<cstring> #include<algorithm> # ...

  6. POJ 1151 扫描线 线段树

    题意:给定平面直角坐标系中的N个矩形,求它们的面积并. 题解:建立一个四元组(x,y1,y2,k).(假设y1<y2)用来储存每一条线,将每一条线按x坐标排序.记录所有的y坐标以后排序离散化.离 ...

  7. 2018 - Start Up

    转眼2017已经过去,从大四下学期出来实习,到现在工作一年多了,很遗憾没有经营好自己博客园&CSDN. 献上一篇鼓励工程师写blog的博客:https://kb.cnblogs.com/pag ...

  8. noi.ac day3t2 染色

    传送门 分析 dp[i][j]为考虑前i个位置,[i-j+1,i]中的颜色互不相同,并且ai-j与这段区间中的某一个位置颜色相同 我们枚举第i+1个位置和[i-j+1,i]中的哪一个颜色相同或者全部不 ...

  9. Entity Framework Tutorial Basics(26):Add Entity Graph

    Add Entity Graph using DbContext: Adding entity graph with all new entities is a simple task. We can ...

  10. Mysql--基本配置

    登录的常用参数 mysql -uroot -p    之后再加上密码 mysql -uroot -p+密码   这个方法不安全 mysql -hlocalhost -uroot -p  之后再加上密码 ...