静态区间第K大

本文详细介绍了POJ2104题目的多种解决方法,包括主席树、划分树、离线处理等算法。通过实例解析,帮助读者掌握不同算法的应用场景与实现细节。

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

<a target=_blank href="http://poj.org/problem?id=2104" target="_blank"><span style="font-size:24px;">POJ 2104</span></a>

POJ 2761

做法好多,主席树,划分树,离线处理(曼哈顿最小生成树?)+BST(Treap or Splay or SBT),貌似分治+BIT也可以,不过懒得搞了。

以后复习模板时用得上。

主席树:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
struct Node{
	int l,r,w;
}tr[N*20];
int a[N],b[N],rank[N],root[N],sz;
void ins(int &i,int l,int r,int x){
	tr[++sz]=tr[i];i=sz;
	tr[i].w++;
	if(l==r)return;
	int m=l+r>>1;
	if(x<=m)ins(tr[i].l,l,m,x);
	else ins(tr[i].r,m+1,r,x);
}
int query(int i,int j,int l,int r,int k){
	if(l==r)return l;
	int m=l+r>>1;
	int tmp=tr[tr[j].l].w-tr[tr[i].l].w;
	if(k<=tmp)return query(tr[i].l,tr[j].l,l,m,k);
	else  return query(tr[i].r,tr[j].r,m+1,r,k-tmp);
}
inline bool cmp(int i,int j){
	return a[i]<a[j];
}
int main(){
	int n,m;scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);rank[i]=i;
	}
	sort(rank+1,rank+1+n,cmp);
	for(int i=1;i<=n;i++)b[rank[i]]=i;
	for(int i=1;i<=n;i++){
		root[i]=root[i-1];
		ins(root[i],1,n,b[i]);
	}
	int x,y,k;
	while(m--){
		scanf("%d%d%d",&x,&y,&k);
		int tmp=query(root[x-1],root[y],1,n,k);
		printf("%d\n",a[rank[tmp]]);
	}
	return 0;
}


### 求解区间第 k 小问题的方法 #### 方法一:基于快速选择算法的解决方案 快速选择是一种用于查找数组中第 k 或第 k 小元素的选择算法。该算法的时间复杂度平均情况下为 O(n),最坏情况下为 O(n²)[^1]。 ```python def quick_select(nums, left, right, k_smallest): if left == right: return nums[left] pivot_index = partition(nums, left, right) if k_smallest == pivot_index: return nums[k_smallest] elif k_smallest < pivot_index: return quick_select(nums, left, pivot_index - 1, k_smallest) else: return quick_select(nums, pivot_index + 1, right, k_smallest) def partition(nums, left, right): pivot_value = nums[right] store_index = left for i in range(left, right): if nums[i] < pivot_value: nums[store_index], nums[i] = nums[i], nums[store_index] store_index += 1 nums[right], nums[store_index] = nums[store_index], nums[right] return store_index ``` #### 方法二:线段树查询 对于静态区间的频繁查询场景,可以预先构建一棵线段树来加速查询过程。预处理时间为 O(n log n),每次查询时间复杂度为 O(log n)。 ```cpp struct SegmentTree { int tree[N * 4]; void build(int node, int start, int end) { ... } int query_kth(int node, int start, int end, int l, int r, int k) { ... } }; ``` #### 方法三:平衡二叉搜索树(BST) 通过维护一颗支持动态插入删除操作并能高效统计子节点数量的 BST 来解决问题。这种做法适合于需要不断更新序列的情况,在此结构上执行单次插入/删除以及秩查询的操作均为 O(log n)[^1]。 #### 方法四:分块思想 将整个数组分成若干个小块,每一块内部有序排列;当询问某一段区间内的第 K 小值时,则只需考虑跨越边界部分加上两端完整的块即可得到答案。这种方法可以在常数时间内完成初始化工作,并且能够在线性扫描的基础上获得较好的性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值