题意:给n个数,m次询问,每次询问L到R中第k小的数是哪个
算法1:划分树
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std; const int mx=1e5+;
int tree[][mx];
int sortt[mx];
int sum[][mx]; void build(int l,int r,int c)
{
if (l==r) return ;
int m=(l+r)>>;
int isame=m-l+;
int pl=l,pr=m+;
for (int i=l;i<m;i++)
if (tree[c][i]<sortt[m]) isame--;
for (int i=l;i<=r;i++){
if (i==l) sum[c][i]=;
else sum[c][i]=sum[c][i-];
if (tree[c][i]<sortt[m]){
tree[c+][pl++]=tree[c][i];
sum[c][i]++;
}
else if ( tree[c][i]==sortt[m]&&isame){
isame--;
tree[c+][pl++]=tree[c][i];
sum[c][i]++;
}
else tree[c+][pr++]=tree[c][i];
}
build(l,m,c+);
build(m+,r,c+);
} int query(int L,int R,int l,int r,int c,int k){
if (L==R) return tree[c][L];
int s,ss;
if (l==L){
s=;
ss=sum[c][r];
}
else{
s=sum[c][l-];
ss=sum[c][r]-s;
}
int m=(L+R)>>;
if (k<=ss) return query(L,m,L+s,L+s+ss-,c+,k);
return query(m+,R,m++l-L-s,m++r-L-s-ss,c+,k-ss);
} int main(){
int n,m;
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++){
scanf("%d",&sortt[i]);
tree[][i]=sortt[i];
}
sort(sortt+,sortt++n);
build(,n,);
while (m--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",query(,n,l,r,,k));
} }
算法2:主席树
/*************************************************************
算法:主席树
思想:建n+1棵线段树,每颗线段数结构都是一样,先建一棵空树,然
后每棵树都在前一棵树的基础上进行修改。
把样例按照代码模拟一遍,就很容易理解了。
**************************************************************/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std; const int mx=1e5+;
struct Tree ///树的节点
{
int l,r; ///树的区间
int ls,rs; ///树的左右孩子
int sum;
};
Tree tree[mx*];
int a[mx],b[mx];
int s[mx],cnt; void build(int l,int r,int &node) ///建空树,和线段树差不多
{
node=++cnt;
tree[node].l=l;
tree[node].r=r;
tree[node].sum=;
if (l==r) return ;
int m=(l+r)/;
build(l,m,tree[node].ls);
build(m+,r,tree[node].rs);
} void inser(int n1,int &n2,int pos) ///在上一棵树的基础上建立新树
{
n2=++cnt;
tree[n2].l=tree[n1].l; ///区间和上一棵树一样
tree[n2].r=tree[n1].r;
tree[n2].rs=tree[n1].rs; ///保证没有修改的部分和上一棵树一样
tree[n2].ls=tree[n1].ls;
tree[n2].sum=tree[n1].sum+;
if (tree[n1].l==tree[n1].r) return ;
int m=(tree[n1].l+tree[n1].r)/;
if (pos<=m) inser(tree[n1].ls,tree[n2].ls,pos);
else inser(tree[n1].rs,tree[n2].rs,pos);
} int query(int n1,int n2,int k) ///查询的k小的树
{
if (tree[n1].l==tree[n1].r)
{
return b[tree[n1].l];
}
int cut=tree[tree[n2].ls].sum-tree[tree[n1].ls].sum;
if (cut>=k) return query(tree[n1].ls,tree[n2].ls,k);
return query(tree[n1].rs,tree[n2].rs,k-cut);
} int main()
{
int n,m;
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+,n+b+);
cnt=;
build(,n,s[]);
for (int i=;i<=n;i++)
{
int pos=lower_bound(b+,b+n+,a[i])-b; ///找的a[i]要放的位置
inser(s[i-],s[i],pos);
}
while (m--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",query(s[l-],s[r],k));
}
}