可持久化权值线段树;
root数组记录第i版本根, 每次建树时只新建当前位相关子节点, 不相关子节点直接用上一版本的原节点
有前缀和及权值树性质, 可区间查询k小数
1.查询区间第k小
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN = 1e5 + 10;
struct prt
{
struct node { int lson, rson, num;} T[MAXN * 40];
int root[MAXN], cnt;
prt() { cnt = 0; }
void update(int l, int r, int &now, int pre, int a) //新建一支
{
now = ++cnt;
T[now] = T[pre];
T[now].num++;
if(l == r) return ;
int mid = (l + r) >> 1;
if(a <= mid) update(l, mid, T[now].lson, T[pre].lson, a);
else update(mid + 1, r, T[now].rson, T[pre].rson, a);
}
int query(int l, int r, int now, int pre, int k) //查询区间排名为K的映射元素值
{
if(l == r) return l;
int mid = (l + r) >> 1;
int lnum = T[T[now].lson].num - T[ T[pre].lson ].num;
if(k <= lnum) return query(l, mid,T[now].lson, T[pre].lson, k);
else return query(mid + 1, r, T[now].rson, T[pre].rson, k - lnum);
}
};
struct lsh
{
int v[MAXN], vl;
lsh() { vl = 0; }
void pb(int val) { v[vl++] = val; } //向后加元素
void init() { sort(v, v + vl); vl = unique(v, v + vl) - v; } //初始化排序,重置大小
int find(int val) { return lower_bound(v, v + vl, val) - v;} //查找元素下标
int get(int pos) { return v[pos]; } //通过下标返回元素
};
int a[MAXN];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n, m;
scanf("%d%d", &n, &m);
lsh V;
prt T;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
V.pb(a[i]);
}
V.init();
for(int i = 1; i <= n; i++)
T.update(0, n, T.root[i], T.root[i - 1], V.find(a[i]));
int a, b, k;
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &a, &b, &k);
printf("%d
", V.get( T.query(0, n, T.root[b], T.root[a - 1], k) ) );
}
}
return 0;
}