题目链接
题意,给你一组数据,m 个询问
每次询问,区间 [ i , j ] 中第 K 大的数是多少,
两个算法,一个是线段树,一个是平方分割。
一、线段树,
这次线段树的每个节点上记录的不是数值了,而是保存了一个序列。
然后二分结果,在线段树种查询这个结果在区间中排多少,最终把值找出来,
线段树节点保存数列是有序的,用到 STL 的一个merge 函数把两个儿子的数列合并。前提是两个儿子的数列也是有序的。
merge(dat[f[p].l].begin(),dat[f[p].l].end(),dat[f[p].r].begin(),dat[f[p].r].end(),dat[p].begin());
#include <vector>
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
struct segtree{
int l,r,a,b;
int cal_mid(){
return (a + b) / 2;
}
}f[N*2];
vector<int>dat[N*2];
int n,m,k,c[N],t,x,y,z,d[N];
void build(int p, int a, int b){
f[p].a = a; f[p].b = b;
if (a + 1 == b){
dat[p].push_back(c[a]);
return;
}
int m = f[p].cal_mid();
t++; f[p].l = t; build(t,a,m);
t++; f[p].r = t; build(t,m,b);
dat[p].resize(b-a);
merge(dat[f[p].l].begin(),dat[f[p].l].end(),dat[f[p].r].begin(),dat[f[p].r].end(),dat[p].begin());
return;
}
int Qurey(int p){
int sum = 0;
if (x <= f[p].a && y >= f[p].b-1){
return upper_bound(dat[p].begin(),dat[p].end(),d[k])-dat[p].begin();
}
int m = f[p].cal_mid();
if (x < m) sum += Qurey(f[p].l);
if (y >= m) sum += Qurey(f[p].r);
return sum;
}
int main() {
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; i++) {
scanf("%d", &c[i]);
d[i] = c[i];
}
sort(d+1,d+n+1);
t = 1;
build(1,1,n+1);
for (int i = 0; i < m; i++){
scanf("%d%d%d",&x,&y,&z);
int l = 1,r = n,ans,tt;
while(l <= r){
k = (l + r) / 2;
tt = Qurey(1);
if (tt < z) l = k +1; else {
ans = k;
r = k - 1;
}
}
printf("%d\n",ans);
}
return 0;
}