题目链接

主席树=可持久化权值线段树。

如果你不会可持久化线段树,请右转

如果你不会权值线段树,请自行脑补,就是线段树维护值域里有多少个数出现。

可持久化线段树是支持查询历史版本的。

我们对每个数都进行一次基于上个版本的单点修改操作,这样每个版本就是维护的前\(p\)个数,这个权值显然满足可减性。

所以,要查询区间\([l,r]\)的第\(k\)大时,我们就用第\(r\)个版本减去第\(l-1\)个版本,我们就得到了一颗\([l,r]\)的权值线段树,然后跑第\(k\)小就简单了:

如果左儿子有大于等于\(k\)个数,就继续去左儿子找第\(k\)小,否则设左儿子的值为\(lcnt\),去右儿子找第\(k-lcnt\)小。

#include <cstdio>
#include <algorithm>
using std::sort;
#define re register
inline int read(){
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }
return s * w;
}
const int MAXN = 200010;
const int MAXM = 200010;
const int MAXMLOGN = 4000010;
struct SegTree{
int lc, rc, cnt;
SegTree(){ lc = rc = cnt = 0; }
}t[MAXMLOGN];
int root[MAXM];
int a[MAXN], c[MAXN], d[MAXN];
int n, m, tot, num;
int build(int l, int r){
int id = ++tot;
if(l == r) return id;
int mid = (l + r) >> 1;
t[id].lc = build(l, mid);
t[id].rc = build(mid + 1, r);
return id;
}
int insert(int now, int l, int r, int x){
int id = ++tot;
t[id] = t[now];
if(l == r){ ++t[id].cnt; return id; }
int mid = (l + r) >> 1;
if(x <= mid) t[id].lc = insert(t[now].lc, l, mid, x);
else t[id].rc = insert(t[now].rc, mid + 1, r, x);
t[id].cnt = t[t[id].lc].cnt + t[t[id].rc].cnt;
return id;
}
int ask(int p, int q, int l, int r, int k){
if(l == r) return l;
int mid = (l + r) >> 1;
int L = t[t[p].lc].cnt - t[t[q].lc].cnt;
if(k <= L) return ask(t[p].lc, t[q].lc, l, mid, k);
else return ask(t[p].rc, t[q].rc, mid + 1, r, k - L);
}
struct divide{
int id, val;
bool operator < (const divide A) const{
return val < A.val;
}
}b[MAXN];
int l, r, k;
int main(){
n = read(); m = read();
for(re int i = 1; i <= n; ++i){
b[i].val = a[i] = read();
b[i].id = i;
}
sort(b + 1, b + n + 1);
b[0].val = -2147483646;
for(int i = 1; i <= n; ++i)
if(b[i].val != b[i - 1].val){
c[b[i].id] = ++num;
d[num] = b[i].val;
}
else c[b[i].id] = num;
root[0] = build(1, num);
for(int i = 1; i <= n; ++i)
root[i] = insert(root[i - 1], 1, num, c[i]);
for(re int i = 1; i <= m; ++i){
l = read(); r = read(); k = read();
printf("%d\n", d[ask(root[r], root[l - 1], 1, num, k)]);
}
getchar();
return 0;
}

最新文章

  1. ASP.NET MVC5+EF6+EasyUI 后台管理系统(66)-MVC WebApi 用户验证 (2)
  2. 1Z0-053 争议题目解析175
  3. 做NavMesh相关工作时收集的一些文章
  4. [转载]TFS体系结构和概念
  5. Cygwin使用方法
  6. MIT 6.828 JOS学习笔记1. Lab 1 Part 1: PC Bootstrap
  7. Java 线程间通讯(共享变量方式)
  8. 1226: [SDOI2009]学校食堂Dining - BZOJ
  9. 删除目录下的所有&quot;.svn&quot;文件
  10. [C# 网络编程系列]专题五:TCP编程
  11. LeetCode201 Bitwise AND of Numbers Range Java 题解
  12. Node.js流
  13. 【回顾整理】暴走的SQL语句练习!!!
  14. hdu 1337 The Drunk Jailer
  15. 在AcGIS随着大数据的生成DEM
  16. Redis几个认识误区
  17. VFL(Visual Format Language)语言
  18. MT【262】一道常见错题
  19. HDU 1045(炮台安置 DFS)
  20. 【Pyton】【小甲鱼】文件

热门文章

  1. 网易云terraform实践
  2. Python连接符的种类和使用区别
  3. 一次和别人争吵一个按钮,点击后显示导航;再点击不显示的效果,是否一定以及必须用js?
  4. Qt QML之不显示标题栏、边框
  5. C++类数组批量赋值
  6. tinymce4.x 上传本地图片 (转载)
  7. Python 并发编程:PoolExecutor 篇
  8. Linux C++线程池实例
  9. 搭建Elasticsearch 5.4分布式集群
  10. 【题解】HNOI2010合唱队