数算实习 k-th number 线段树

本文介绍了一种解决数列中快速查询第K小数的高效算法,通过离散化和二分查找优化查询过程,适用于大规模数据集的查询需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

k-th number

给定数列a1,a2…an,各不相同。要进行m次查询,每次查询 a[L…R] 中第k小的数是什么 (1 <= n <= 100 000, 1 <= m <= 5 000) abs(ai) <= 10^9

样例输入
7 3 //7个数,3次查询
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3
样例输出
5
6
3

#include <iostream>
#include <algorithm>
using namespace std;

int Array[100002];            //Array记录原始数组
int order[100002];            //order记录数组中每个元素对应的编号(从小到大)   离散化
int sortA[100002];            //sortA用来对数组排序并记录
int p;

struct tree
{
	int* store;
	int len;
	int l;
	int r;
	tree* left;
	tree* right;
};
void buildtree(tree* root, int L, int R)          
//将order数组第L到第R个元素,并将其排序后放入store数组中,方便之后用upper_bound函数进行二分查找
{
	root->len = R - L + 1;
	root->l = L;
	root->r = R;
	root->store = new int[root->len + 10];
	for (int i = 1; i <= root->len; i++)
	{
		root->store[i] = order[L + i - 1];
	}
	sort(root->store, root->store + root->len + 1);        //对store数组进行处理
	root->left = new tree;
	root->right = new tree;
	if (L == R)                        //分解到了最底层
		return;
	int mid = (L + R) / 2;
	buildtree(root->left, L, mid);
	buildtree(root->right, mid + 1, R);
}
void quary(tree* root, int L, int R, int mid)
{
	if (L == root->l&&R == root->r)
	{
		p += upper_bound(root->store + 1, root->store + root->len + 1, mid) - (root->store + 1);
		//store数组已经排序,看这个子结点中比mid小或相等的元素有多少
		return;
	}
	else
	{
		int Mid = (root->l + root->r) / 2;
		if (R <= Mid)
			quary(root->left, L, R, mid);
		else if (L >= Mid + 1)
			quary(root->right, L, R, mid);
		else
		{
			quary(root->left, L, Mid, mid);
			quary(root->right, Mid + 1, R, mid);
		}
	}
}

int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		cin >> Array[i];
		sortA[i] = Array[i];
	}
	sort(sortA + 1, sortA + n + 1);
	for (int i = 1; i <= n; i++)
	{
		order[i] = lower_bound(sortA + 1, sortA + 1 + n, Array[i]) - sortA;
	}
	tree* root = new tree;
	buildtree(root, 1, n);
	while (m--)
	{
		int l, r;
		int k;
		cin >> l >> r >> k;
		int tl = 1;
		int tr = n;
		if (l == r)
		{
			printf("%d\n", Array[l]);
			continue;
		}
		int mid = (tl + tr) / 2;
		while (1)
		{
			p = 0;
			if (tl == tr)
			{
				printf("%d\n", sortA[tl]);
				break;
			}
			quary(root, l, r, mid);
			if (p >= k)
			{
				tr = mid;
				mid = (tl + mid) / 2;
			}
			else
			{
				tl = mid + 1;
				mid = (tr + mid) / 2;
			}
		}
	}

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值