传送门

  • 查询 kkk 在区间内的排名
  • 查询区间内排名为 kkk的值
  • 修改某一位值上的数值
  • 查询 kkk 在区间内的前驱(前驱定义为严格小于 xxx,且最大的数,若不存在输出 −2147483647-2147483647−2147483647)
  • 查询 kkk 在区间内的后继(后继定义为严格大于 xxx,且最小的数,若不存在输出 214748364721474836472147483647)

分析

对于静态区间第K大来说,那就上主席树吧
如果动态的话,就树套树了
如果是双动态的话,那就树套树套树了(大雾)
此时我们只需要实现三个功能即可

  • 根据值查询排名
  • 根据排名查值
  • 修改值

对于一棵静态区间第K大的主席树来说,维护的是一个前缀和
一旦某一个版本(位置)的值改变了,那么必须重构这个版本(位置)往后的所有版本状态
此时修改复杂度最差为 n∗log(n)n*log(n)n∗log(n),我不能接受
那么什么能够在短时间维护一个前缀和的修改呢?
我们想到了树状数组,每次log(n)log(n)log(n)时间修改一个位置
查询也是log(n)log(n)log(n)的

我们对树状数组和主席树进行组装,树状数组的每一个节点都表示着主席树的某一系列版本
对于要查询某个区间的版本情况,找到需要的左端点版本对应的一系列树状数组维护的版本l−1l-1l−1,以及右端点版本rrr(共有将近log(n)log(n)log(n)个版本,使用 lowbit 预处理出这一系列版本)
在这两个主席树系列版本上进行差分

修改值也是先预处理出这一系列版本,在这log(n)log(n)log(n)个版本中更新

对于第三第四个操作
通过第一个和第二个操作的组合,就能实现

代码

//P3380
/*@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("P3380_1.in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;int arr[MAX_N];
int uniarr[MAX_N];
int unicnt = 0;struct Qr {int opt, l, r, k;
}qr[MAX_N];struct Tr {int k, l, r;
}tr[MAX_N*25];int indx = 0;
int root[MAX_N];void update(int&rt, int l, int r, int x, int k) {if (!rt) rt = ++indx;tr[rt].k += k;if (l == r) {return;}int mid = l + ((r-l)>>1);if (x <= mid) update(tr[rt].l, l, mid, x, k);else update(tr[rt].r, mid+1, r, x, k);
}int query(int rt, int l, int r, int x, int y) {if (!rt) return 0;if (x <= l && r <= y) {return tr[rt].k;}int mid = l + ((r-l)>>1);if (y <= mid) return query(tr[rt].l, l, mid, x, y);if (x  > mid) return query(tr[rt].r, mid+1, r, x, y);return query(tr[rt].l, l, mid, x, y) + query(tr[rt].r, mid+1, r, x, y);
}int cnt[2];
int son[2][MAX_N];int kth(int l, int r, int k) {if (l == r) {return l;}int mid = l + ((r-l)>>1);int lsum = 0, sum = 0;for (int i = 1; i <= cnt[1]; ++i) {sum += tr[son[1][i]].k;lsum += tr[tr[son[1][i]].l].k;}for (int i = 1; i <= cnt[0]; ++i) {sum -= tr[son[0][i]].k;lsum -= tr[tr[son[0][i]].l].k;}if (lsum >= k) {for (int i = 1; i <= cnt[0]; ++i) {son[0][i] = tr[son[0][i]].l;}for (int i = 1; i <= cnt[1]; ++i) {son[1][i] = tr[son[1][i]].l;}return kth(l, mid, k);} else {for (int i = 1; i <= cnt[0]; ++i) {son[0][i] = tr[son[0][i]].r;}for (int i = 1; i <= cnt[1]; ++i) {son[1][i] = tr[son[1][i]].r;}return kth(mid+1, r, k - lsum);}
}int rak(int x) {int sum = 0;int t;for (int i = 1; i <= cnt[1]; ++i) {t = query(son[1][i], 1, unicnt, 1, x);sum += t;}for (int i = 1; i <= cnt[0]; ++i) {t = query(son[0][i], 1, unicnt, 1, x);sum -= t;}return sum;
}inline int lowbit(int x) {return x&-x;
}void modify(int x, int k, int w) {while (x <= N) {update(root[x], 1, unicnt, k, w);x += lowbit(x);}
}void init(int l, int r) {memset(cnt, 0, sizeof cnt);--l;while (l) {son[0][++cnt[0]] = root[l];l -= lowbit(l);}while (r) {son[1][++cnt[1]] = root[r];r -= lowbit(r);}
}/**
9 1
4 2 2 1 9 4 0 1 1
2 1 4 3
**/
void solve(){sc("%lld%lld", &N, &M);uniarr[++unicnt] = -2147483647;uniarr[++unicnt] = 2147483647;for (int i = 1; i <= N; ++i) {sc("%lld", &arr[i]);uniarr[++unicnt] = arr[i];}int opt, l, r, k;for (int i = 1; i <= M; ++i) {sc("%lld%lld%lld", &qr[i].opt, &qr[i].l, &qr[i].r);if (qr[i].opt == 1) {sc("%lld", &qr[i].k);uniarr[++unicnt] = qr[i].k;} else if (qr[i].opt == 2) {sc("%lld", &qr[i].k);} else if (qr[i].opt == 3) {qr[i].k = qr[i].r;uniarr[++unicnt] = qr[i].k;} else if (qr[i].opt == 4) {sc("%lld", &qr[i].k);uniarr[++unicnt] = qr[i].k;} else {sc("%lld", &qr[i].k);uniarr[++unicnt] = qr[i].k;}}sort(uniarr+1, uniarr+1+unicnt);unicnt = unique(uniarr+1, uniarr+1+unicnt) - uniarr - 1;for (int i = 1; i <= N; ++i) {arr[i] = lower_bound(uniarr+1, uniarr+1+unicnt, arr[i]) - uniarr;modify(i, arr[i], 1);}for (int i = 1; i <= M; ++i) {if (qr[i].opt != 2) qr[i].k = lower_bound(uniarr+1, uniarr+1+unicnt, qr[i].k) - uniarr;if (qr[i].opt == 1) {init(qr[i].l, qr[i].r);pr("%lld\n", rak(qr[i].k-1) + 1);} else if (qr[i].opt == 2) {init(qr[i].l, qr[i].r);pr("%lld\n", uniarr[kth(1, unicnt, qr[i].k)]);} else if (qr[i].opt == 3) {modify(qr[i].l, arr[qr[i].l], -1);modify(qr[i].l, arr[qr[i].l] = qr[i].k, 1);} else if (qr[i].opt == 4) {init(qr[i].l, qr[i].r);int rk = rak(qr[i].k-1);init(qr[i].l, qr[i].r);pr("%lld\n", uniarr[kth(1, unicnt, rk)]);} else {init(qr[i].l, qr[i].r);int rk = rak(qr[i].k);init(qr[i].l, qr[i].r);pr("%lld\n", uniarr[kth(1, unicnt, rk+1)]);}}}signed main()
{#ifndef ONLINE_JUDGEFILE_INFILE_OUT#endifint T = 1;//cin >> T;while (T--) solve();return AC;
}

P3380 【模板】二逼平衡树(树套树)相关推荐

  1. BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)

    我实在是不想再打一遍树状数组套替罪羊树了... 然后在普通平衡树瞎逛的时候找到了以前看过vector题解 于是我想:为啥不把平衡树换成vector呢??? 然后我又去学了一下ZKW线段树 就用ZKW线 ...

  2. 洛谷 P3380 bzoj3196 Tyvj1730 【模板】二逼平衡树(树套树)

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

  3. [luogu3380][bzoj3196]【模板】二逼平衡树【树套树】

    题目地址 [洛谷传送门] 题目大意 区间查询k的排名,查找k排名的数,单点修改,区间前驱,区间后继. 感想 真的第一次写树套树,整个人都不对了.重构代码2次,发现样例都过不了,splay直接爆炸,可能 ...

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

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

  5. 【BZOJ3196】【Tyvj1730】二逼平衡树,第一次的树套树(线段树+splay)

    传送门1 传送门2 写在前面:创造迄今最长的正常代码的记录 思路:个人感觉这个树套树就是对线段树的每个区间建一棵splay来维护,最初觉得这个方法会爆T爆M--(实际上真的可能会爆).对于5个操作,我 ...

  6. 【Luogu】P3380树套树模板(线段树套Splay)

    题目链接 幸甚至哉,歌以咏志. 拿下了曾经是那么遥不可及的线段树,学会了曾经高不可攀的平衡树,弄懂了装B的时候才挂在嘴边的树套树. 每道模板都是链上的一颗珠子.把它们挨个串起来,就成为我成长的历程. ...

  7. 树套树-线段树套平衡树

    作用 线段树的作用是区间修改和查询,平衡树的作用是查询第k大,k的排名,前驱,后继.这两个结合起来,就变成了可以区间修改和查询第k大,k的排名,前驱,后继的数据结构:树套树-线段树套平衡树. 实现 先 ...

  8. Bzoj 3196 Tyvj 1730 二逼平衡树

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

  9. 数据结构:树套树-替罪羊树套权值线段树

    BZOJ3065 本题是在BZOJ上的处女A,实在不应该拿这样一道题来开头 平衡树套线段树应该是树套树问题里比较难的一种了,当然我记得还有一个替罪羊树套Trie树的题,我是不信自己能写出来的. 外层的 ...

最新文章

  1. 与后台交互方法一 ——Ajax
  2. 2020中国高校薪资排行出炉!好过双一流的高校原来这么多!
  3. Android 使用自带的HttpClient进行https请求出现403的解决过程记录
  4. LAMP之Apache
  5. 【公开课预告】:超低延迟下的实时合唱体验升级
  6. CodeChef Chef and Churu [分块]
  7. idea 不能及时编译_您是否能及时编译?
  8. Ext JS 4.1 RC1发布
  9. 数据结构-- 线性表之链式存储
  10. java视频压缩 lz4_关于LZMA和LZ4压缩的疑惑解析
  11. lavarel php区别,laravel中{{}}和{!! !!}的区别详解
  12. QT for android 比较完美解决 全屏问题
  13. cf1173 D. Nauuo and Circle
  14. 4月升级鸿蒙,华为鸿蒙系统4月升级适配名单一览
  15. IDEA 这么设置 Maven,再也不用担心依赖下载失败了
  16. python爱好者社区 周琦_这么多年来,我算想明白了!
  17. SQL2008 SP3下载
  18. DNS服务器的安装与配置
  19. Selenium学习笔记
  20. 直截了当地解释 ERC-3525 与 ERC-1155 的差别

热门文章

  1. 网络安全与渗透:xss 跨站脚本攻击(十二)此生无悔入华夏,男儿何不带吴钩
  2. 跟阿里巴巴学开会,我们拉着5位CEO聊如何“捅刀子”
  3. tensorflow代码全解析 -3- seq2seq 自动生成文本
  4. 基于STM32的智能风扇的制作
  5. 原生JS实现移动端弹幕(虎牙,斗鱼简易版)
  6. 关于mysql blob 存取乱码问题
  7. uniapp 动态切换应用图标、名称插件(如新年、国庆等) Ba-ChangeIcon
  8. 如何用TensorFlow开发不一样的AI足球智能分析预测软件
  9. Keyshot+AD渲染PCB效果图
  10. 立创开源丨基于GD32E230C8T6芯片的开发评估板