主席树学习------可持久化权值线段树
静态区间第k小
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200005;
int n,q,tot,rt[maxn],a[maxn],b[maxn];
struct chairman_tree
{
int son[2],siz;
} node[maxn*50];
void build(int &rt,int l,int r) //建一颗空树
{
rt = ++tot; //动态开点
if(l==r) return;
int mid = (l + r) >> 1;
build(node[rt].son[0],l,mid);
build(node[rt].son[1],mid+1,r);
}
void update(int &rt,int last,int l,int r,int val) //插入节点,实际上是从上往下新建一条链
{
node[rt=++tot] = node[last]; //复制上一个树的节点
++node[rt].siz; //修改大小
if(l==r) return;
int mid = (l + r) >> 1;
if(val<=mid) update(node[rt].son[0],node[last].son[0],l,mid,val); //寻找继续修改的位置,是左子树还是右子树
else update(node[rt].son[1],node[last].son[1],mid+1,r,val);
}
int query(int rt1,int rt2,int l,int r,int k) //询问,利用前缀和思想,返回第k小的数的位置
{
if(l==r) return l;
int mid = (l + r) >> 1;
if(node[node[rt2].son[0]].siz-node[node[rt1].son[0]].siz>=k)
return query(node[rt1].son[0],node[rt2].son[0],l,mid,k);
else return query(node[rt1].son[1],node[rt2].son[1],mid+1,r,k-node[node[rt2].son[0]].siz+node[node[rt1].son[0]].siz);
}
signed main()
{
scanf("%d %d",&n,&q);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);b[i]=a[i];
}
sort(b+1,b+1+n);
int cnt = unique(b+1,b+1+n)-(b+1); //离散化
//build(rt[0],1,cnt); //这一步可以不用
for(int i=1;i<=n;++i)
update(rt[i],rt[i-1],1,cnt,lower_bound(b+1,b+cnt+1,a[i])-b); //用离散化后的值更新
int l,r,k;
for(int i=1;i<=q;++i)
{
scanf("%d %d %d",&l,&r,&k);
printf("%d\n",b[query(rt[l-1],rt[r],1,cnt,k)]); //输出原来的值
}
return 0;
}