主席树模板题,求n个数中,第l个数到第r个数的第k小的数
#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
struct node
{
int data,l,r;
} tree[210000<<5];//主席树一般开32倍的空间
int a[210000], b[210000],T[210000],cnt;
int build(int l, int r)//建空数
{
int num = ++cnt;
tree[num].data = 0;
if(l < r)
{
tree[num].l = build(l,mid);
tree[num].r = build(mid+1,r);
}
return num;
}
int update(int pre,int l, int r,int x)//在主席树上添加一个线段树
{
int num = ++ cnt;
tree[num].l = tree[pre].l;//这个线段树的左右子树继承上一个线段树根节点的左右子树
tree[num].r = tree[pre].r;
tree[num].data = tree[pre].data +1;//因为添加了一个数,data+1
if(l < r)
{
if(x <= mid)
tree[num].l = update(tree[pre].l,l,mid,x);
else
tree[num].r = update(tree[pre].r,mid+1,r,x);
}
return num;
}
int query(int u, int v,int l,int r,int k)
{
if(l == r)
return l;
int x = tree[tree[v].l].data -tree[tree[u].l].data;//两颗线段树做差,得到的是以x到y输入的数,建的线段树
if(x >= k)
return query(tree[u].l,tree[v].l,l,mid,k);//在左子树中是第k个数
else
return query(tree[u].r,tree[v].r,mid+1,r,k-x);//在右子树中是第k-x个数(减去左子树的数的数量)
}
int main()
{
int i,m,n,q,x,y,z;
scanf("%d %d",&n,&q);
for(i = 1; i <= n; i ++)
{
scanf("%d",&a[i]);
b[i] = a[i];
}
sort(b+1,b+n+1);
m = unique(b+1,b+n+1) -(b+1);//排序好,去掉重复元素的数组的长度
cnt = 0;
T[0] = build(1,m);
for(i = 1; i <= n; i ++)
{
x = lower_bound(b+1,b+1+m,a[i]) -b;//a[i]在b中的位置,
T[i] = update(T[i-1],1,m,x);//每输入一个数,则在主席树中添加一颗线段树,以记录历史
}
while(q --)
{
scanf("%d %d %d",&x, &y, &z);
int t = query(T[x-1],T[y],1,m,z);
printf("%d\n",b[t]);
}
return 0;
}