给出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; }
时间: 2024-10-12 19:27:45