51nod 1175 区间中第K大的数(主席树)
发布日期:2021-11-02 09:48:58 浏览次数:2 分类:技术文章

本文共 2831 字,大约阅读时间需要 9 分钟。

1175 区间中第K大的数

一个长度为N的整数序列,编号0 - N - 1。进行Q次查询,查询编号i至j的所有数中,第K大的数是多少。

例如: 1 7 6 3 1。i = 1, j = 3,k = 2,对应的数为7 6 3,第2大的数为6。
输入
第1行:1个数N,表示序列的长度。(2 <= N <= 50000)
第2 - N + 1行:每行1个数,对应序列中的元素。(0 <= S[i] <= 10^9)
第N + 2行:1个数Q,表示查询的数量。(2 <= Q <= 50000)
第N + 3 - N + Q + 2行:每行3个数,对应查询的起始编号i和结束编号j,以及k。(0 <= i <= j <= N - 1,1 <= k <= j - i + 1)

输出

共Q行,对应每一个查询区间中第K大的数。

输入样例

5

1
7
6
3
1
3
0 1 1
1 3 2
3 4 2

输出样例

7

6
1

代码实现

下面代码是求第k小的模板修改而来的。

#include
using namespace std;const int N = 200000 + 5;int n, m, size, cnt = 0;int w[N];//用于记录原数组int s[N];//用于记录去重排序后数组int rk[N];//用于记录原数组的元素是第几小int root[N];//用于记录每个根节点的编号// 主席树struct President_tree {
// ls,rs分别记录一个节点的左右儿子编号,sum记录经过该节点的次数 int ls, rs, sum;} t[N * 20];inline int read() {
int x = 0; int flagK = 1; char c = getchar(); while (!isdigit(c)) {
if (c == '-')flagK = -1; c = getchar(); } while (isdigit(c)) {
x = x * 10 + c - '0'; c = getchar(); } x *= flagK; return x;}void build(int &node, int l, int r) {
// 建一颗空树(虽然不建也没什么关系) node = ++cnt; if (l == r) return; int mid = (l + r >> 1); build(t[node].ls, l, mid); build(t[node].rs, mid + 1, r);}void updata(int &node, int last, int l, int r, int s) {
node = ++cnt; t[node] = t[last]; // 通过上一次修改的值来修改 ++t[node].sum; if (l == r) return; int mid = (l + r >> 1); if (s <= mid) {
// 如果最后要插到叶子节点的位置在mid左边,就往左插 updata(t[node].ls, t[last].ls, l, mid, s); } else {
// 同理 updata(t[node].rs, t[last].rs, mid + 1, r, s); }}int query(int node, int last, int l, int r, int k) {
if (l == r) {
//查询到了叶子节点时,就找到了是在去重排序后序列中第L位置的值 return s[l]; } // 类似于splay的查询第k大 int sum = t[t[node].ls].sum - t[t[last].ls].sum, mid = (l + r >> 1); if (k <= sum) {
return query(t[node].ls, t[last].ls, l, mid, k); } else {
return query(t[node].rs, t[last].rs, mid + 1, r, k - sum); }}int main() {
int x, y, k; n = read(); for (int i = 1; i <= n; i++) {
w[i] = read(); } memcpy(s, w, sizeof(s)); sort(s + 1, s + n + 1); // unique可以将数组去重,因为unique返回的是一个地址,而数组以1开始,所以排序后的数组大小为这个值 size = unique(s + 1, s + n + 1) - s - 1; build(root[0], 1, size); // 处理每个数字是第几小,要在已经去重后的s数组中查找 for (int i = 1; i <= n; i++) {
rk[i] = lower_bound(s + 1, s + size + 1, w[i]) - s; } for (int i = 1; i <= n; i++) {
// 将每次修改后的线段树存下来,以根节点来找整棵树 updata(root[i], root[i - 1], 1, size, rk[i]); } m = read(); for (int i = 1; i <= m; i++) {
// x y 的正常区间为 1到n x = read(); y = read(); k = read(); // 当求最大且区间为 0到n-1 时需要这样改 k = y - x + 2 - k; x++, y++; printf("%d\n", query(root[y], root[x - 1], 1, size, k)); } return 0;}

转载地址:https://blog.csdn.net/weixin_43820352/article/details/111238142 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:51nod 1693 水群(思维,最短路,spfa)
下一篇:文件上传到服务器(Java 工具类)

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月13日 07时00分57秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

08 【多线程高并发】Java线程间通信的方式 2019-04-26
【数据结构与算法】什么是跳表?通俗易懂来理解跳表 2019-04-26
【数据结构与算法】什么是图?图是什么?快速带你回顾图有关的知识点 2019-04-26
【数据结构与算法】什么是串?什么是KMP算法?字符串匹配是什么? 2019-04-26
【数据结构与算法】什么是布隆过滤器?如何防止缓存穿透的问题? 2019-04-26
【Java锁体系】CopyOnWriteArrayList是什么?线程安全的arraylist是哪个? 2019-04-26
【面试题目】Java设计模式你有哪些了解?说几个常用的。 2019-04-26
【计算机操作系统】常说的死锁是什么?死锁产生的必要条件是什么?死锁的解决策略是什么? 2019-04-26
【计算机操作系统】进程管理详解?进程与线程区别是什么?进程调度的算法有哪些?进程通信有哪些? 2019-04-26
【计算机操作系统】虚拟内存是什么?分页系统地址映射?页面置换算法有哪些?分段地址映射又是什么? 2019-04-26
【计算机操作系统】设备管理?磁盘结构是怎么样的?磁盘调度算法有哪些? 2019-04-26
【多线程高并发】为什么要使用多线程?创建多少个线程合适呢? 2019-04-26
【多线程与高并发】 Java两个线程轮流打印1-100两个数?多线程轮流打印数字? 2019-04-26
【多线程与高并发】 Java两个线程轮流打印字符串? 2019-04-26
【Linux命令篇】Linux命令实践 2019-04-26
【Leetcode单调队列】Leetcode239 滑动窗口最大值 2019-04-26
【Leetcode-单调栈】单调栈相关的题目-下一个更大的元素I 每日温度 2019-04-26
【Leetcode单调队列】- 洛谷P1714切蛋糕 2019-04-26
【Leetcode优先级队列】- 数据流的中位数 2019-04-26
【Leetcode优先级队列】-合并K个升序链表 2019-04-26