给出n,m
n个数字
m次询问,每次询问(l,r)区间的第k小的数
划分树模板 mark一下
#include "stdio.h"
#include "string.h"
#include "algorithm"
using namespace std;
int a[100010],as[100010];
int tree[20][100010];// 记录第i层元素序列
int sum[20][100010];// 记录第i层的1~j划分到左子树的元素个数(包括j)
void build(int c,int l,int r)
{
int mid,i;
int lm; // 记录左区间共有多少个数=as{mid]
int lp; // 左区间的mark
int rp; // 右区间的mark
mid=(l+r)/2;
lm=mid-l+1;
lp=l;
rp=mid+1;
for (i=l;i<=mid;i++)
if (as[i]<as[mid])
lm--;//先假设左边的(mid - l + 1)个数都等于as[mid],然后把实际上小于as[mid]的减去
for (i=l;i<=r;i++)
{
if (i==l)
sum[c][i]=0;
else
sum[c][i]=sum[c][i-1];
if (tree[c][i]==as[mid])
{
if (lm)
{
lm--;
sum[c][i]++;
tree[c+1][lp++]=tree[c][i];
}
else
tree[c+1][rp++]=tree[c][i];
}
else
if (tree[c][i]<as[mid])
{
sum[c][i]++;
tree[c+1][lp++]=tree[c][i];
}
else
tree[c+1][rp++]=tree[c][i];
}
if (l==r) return ;
build(c+1,l,mid);
build(c+1,mid+1,r);
}
int query(int c,int l,int r,int ql,int qr,int k)// 在l-r区间内的 ql-qr区间中的第K小的数
{
int s;//[l, ql)内将被划分到左子树的元素数目
int ss;//[ql, qr]内将被划分到左子树的元素数目
int mid=(l+r)/2;
if (l==r)
return tree[c][l];
if (l==ql)
{
s=0;
ss=sum[c][qr];
}
else
{
s=sum[c][ql-1];
ss=sum[c][qr]-s;
}
if (k<=ss)
return query(c+1,l,mid,l+s,l+s+ss-1,k);
else
return query(c+1,mid+1,r,mid-l+1+ql-s,mid-l+1+qr-s-ss,k-ss);
}
int main()
{
int n,m,i,l,r,k;
while (scanf("%d%d",&n,&m)!=EOF)
{
for (i=1;i<=n;i++)
{
scanf("%d",&a[i]);
tree[0][i]=as[i]=a[i];
}
sort(as+1,as+1+n);
build(0,1,n);
while (m--)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",query(0,1,n,l,r,k));
}
}
return 0;
}