题意:求区间[l,r]中第k小的数
题解:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100001
#define L(u) (u<<1)
#define R(u) (u<<1|1)
#define MID(l, r) ((l+r)>>1)
struct SegTree
{
int l, r;
} node[MAXN*4];
int sortA[MAXN];
int toLeft[20][MAXN]; //toLeft[i]表示[node[u].l, i]区域里有多少个数分到左子树中
int val[20][MAXN];
void build(int u, int l, int r, int h)
{
node[u].l = l;
node[u].r = r;
if(node[u].l == node[u].r) return;
int mid = MID(l, r);
int eqlToLeft = mid - l + 1; //eqlToLeft统计区间[l,r]中与中位数相等且分到左子树中的数的个数
for(int i = l; i <= r ; i++)
if(val[h][i] < sortA[mid])
eqlToLeft--; //先假设左子树中的(mid-l+1)个数都等于中位数,然后把实际上小于中位数的减去
int lpos = l;
int rpos = mid + 1;
int cnt = 0; //统计已经进入左子树的数个数(对于所有等于中位数的数)
for(int i = l ; i <= r ; i++)
{
if(i == l)
toLeft[h][i] = 0;
else
toLeft[h][i] = toLeft[h][i-1];
if(val[h][i] < sortA[mid])
{
toLeft[h][i]++;
val[h+1][lpos++] = val[h][i];
}
else if(val[h][i] > sortA[mid])
val[h+1][rpos++] = val[h][i];
else
{
//对于等于中位数的数,一部分分到左子树,一部分分到右子树
if(cnt < eqlToLeft)
{
cnt++;
toLeft[h][i]++;
val[h+1][lpos++] = val[h][i];
}
else
val[h+1][rpos++] = val[h][i];
}
}
build(L(u), l, mid, h + 1);
build(R(u), mid + 1, r, h + 1);
}
int query(int u, int l, int r, int h, int k)
{
if(l == r) return val[h][l];
int cnt1; //cnt1表示[node[u].l, l-1]有多少个数分到左子树中
int cnt2; //cnt2表示[l,r]有多少个数分到当前区间的左子树中
//[node[u].l, l-1] + [l,r] = [node[u].l, r]
if(l == node[u].l)
{
cnt1 = 0;
cnt2 = toLeft[h][r];
}
else
{
cnt1 = toLeft[h][l-1];
cnt2 = toLeft[h][r] - toLeft[h][l-1];
}
if(cnt2 >= k) //[l,r]区间上有多于k个分到左边,显然去左子树找第k个
{
//计算出新的映射区间,注意:划分树上保证下标的顺序不变
int newl = node[u].l + cnt1; //[node[u].l, l-1]
int newr = node[u].l + cnt1 + cnt2 - 1; //[l,r]
return query(L(u), newl, newr, h + 1, k);
}
else
{
int mid = MID(node[u].l, node[u].r);
int cnt3 = l - node[u].l - cnt1; //cnt3记录node[u].l, l-1]有多少个分到右子树中
int cnt4 = r - l + 1 - cnt2; //cnt4记录[l,r]有多少个分到右子树中
int newl = mid + cnt3 + 1;
int newr = mid + cnt3 + cnt4;
return query(R(u), newl, newr, h+1, k - cnt2);
}
}
int main()
{
int n, m;
while(scanf("%d%d",&n,&m) != EOF)
{
for(int i = 1; i <= n; i++)
{
scanf("%d",&val[0][i]);
sortA[i] = val[0][i];
}
sort(sortA + 1, sortA + 1 + n);
build(1, 1, n, 0);
int l, r, k;
while(m--)
{
scanf("%d%d%d",&l,&r,&k);
int ret = query(1, l, r, 0, k);
printf("%d\n",ret);
}
}
}