主席树用来寻找区间第k小的数的模板
下面是代码:
#include<iostream>
#include<vector>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 2e5+5;
int n,m,cnt,root[maxn],a[maxn],x,y,k;//n个点,m次询问,root存放多颗线段树的根节点,a存放离散化之前的数据
struct node{
int l;//指向左子树
int r;//指向右子树
int sum;//sum表示该节点所管辖区间范围内数的个数
}T[maxn*40];//存放主席树,开40倍保证不会爆掉
vector<int> v;//用于离散化数据
int getid(int x)//得到离散化数据之后x在离散化后数组中的位置
{
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void update(int l,int r,int &x,int y,int pos)
{
T[++cnt]=T[y];
T[cnt].sum++;
x=cnt;
if(l==r) return;
int mid=(l+r)/2;
if(mid>=pos) update(l,mid,T[x].l,T[y].l,pos);
else update(mid+1,r,T[x].r,T[y].r,pos);
}
int query(int l,int r,int x,int y,int k)
{
if(l==r) return l;
int mid=(l+r)/2;
int sum=T[T[y].l].sum-T[T[x].l].sum;
if(sum>=k) return query(l,mid,T[x].l,T[y].l,k);
else return query(mid+1,r,T[x].r,T[y].r,k-sum);
//下面注释掉的是找区间第k大的数的写法
// int sum=T[T[y].r].sum-T[T[x].r].sum;
// if(sum>=k) return query(mid+1,r,T[x].r,T[y].r,k);
// else return query(l,mid,T[x].l,T[y].l,k-sum);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;++i)
{
cin>>a[i];
v.push_back(a[i]);
}
sort(v.begin(),v.end());//使之能够二分查找
v.erase(unique(v.begin(),v.end()),v.end());//删除多余的部分,得到没有重复的vector,数据离散化完毕
for(int i=1;i<=n;++i)
{
update(1,n,root[i],root[i-1],getid(a[i]));//建立主席树,root[i]继承自root[i-1],getid取得要插入的位置
}
for(int i=1;i<=m;++i)
{
cin>>x>>y>>k;
cout<<v[query(1,n,root[x-1],root[y],k)-1]<<endl;
}
return 0;
}