点击查看代码
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);
#define endl '\n'
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
int n, m, cnt = 0; //cnt代表当前的节点编号,这里用到了动态开点的思想
int a[MAXN], b[MAXN], re[MAXN], head[MAXN]; //原数组, b和re数组mp反映射数组, 每个历史版本的线段树的头节点
map<int, int> mp; //离散化
struct Node
{
int l, r, val, lson, rson; //l, r权值区间内有多少个数val,当前节点的左儿子,当前节点的右儿子
} tree[MAXN * 30]; //主席树一般开30,不够再往上10倍开
void build(int l, int r, int cur)
{
tree[cur].l = l, tree[cur].r = r, tree[cur].val = 0;
if (l == r)
return;
tree[cur].lson = ++cnt; tree[cur].rson = ++cnt; //动态开点的思想
int mid = l + r >> 1;
build(l, mid, tree[cur].lson), build(mid + 1, r, tree[cur].rson);
}
void pushup(int cur)
{
tree[cur].val = tree[tree[cur].lson].val + tree[tree[cur].rson].val;
return;
}
void update(int tar, int cur, int pre) //要更新的点建立一棵在前一个版本的基础上建立一棵新树
{
tree[cur].l = tree[pre].l, tree[cur].r = tree[pre].r, tree[cur].val = tree[pre].val; //肯定在前一个版本的基础上,所以先初始化
if (tree[cur].l == tree[cur].r) //准确的到那个数了,就对那个数的权值区间个数++
{
tree[cur].val++;
return;
}
int mid = tree[cur].l + tree[cur].r >> 1;
if (tar <= mid) //说明要更新的点在左子树
{
tree[cur].lson = ++cnt; //动态开点左子树
tree[cur].rson = tree[pre].rson; //右侧的节点不变
update(tar, tree[cur].lson, tree[pre].lson); //继续更新左子树
}
else //说明要更新的点在右子树
{
tree[cur].lson = tree[pre].lson; //左侧的节点不变
tree[cur].rson = ++cnt; //动态开点右子树
update(tar, tree[cur].rson, tree[pre].rson); //继续更新有子树
}
pushup(cur);
}
int query(int k, int cur, int pre)
{
if (tree[cur].l == tree[cur].r) //当前左右区间相等,必然就是这个区间里面第k小的数
return tree[cur].l;
int val = tree[tree[cur].lson].val - tree[tree[pre].lson].val;
if (k <= val) //说明这个第k小在左子树
return query(k, tree[cur].lson, tree[pre].lson);
else //说明这个第k小的在右子树
return query(k - val, tree[cur].rson, tree[pre].rson); //因为左子树已经有val个了,所以这里要先减去val个
}
int main()
{
IOS; cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; ++i)
cin >> a[i], mp[a[i]] = 1;
int pos = 0;
for (auto it = mp.begin(); it != mp.end(); ++it) //离散化处理
it->second = ++pos, re[pos] = it->first;
for (int i = 1; i <= n; ++i)
b[i] = mp[a[i]];
head[0] = 1, cnt = 1;
build(1, mp.size(), head[0]); //先建立一棵空树
for (int i = 1; i <= n; ++i)
{
head[i] = ++cnt; //每一个数对应每一个更新版本,每一个更新版本对应一个cnt, 代表这个版本的头
update(mp[a[i]], head[i], head[i - 1]);
}
int l, r, k;
while (m--)
{
cin >> l >> r >> k;
cout << re[query(k, head[r], head[l - 1])] << endl; //第r个版本和l - 1个历史版本进行计算
}
return 0;
}