POJ - 2104 K-th Number

Posted notnight

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ - 2104 K-th Number相关的知识,希望对你有一定的参考价值。

题目大意:给你n个数,q个询问,每个询问问你在 l 到 r 之间的第k个数是多大。

 

思路:很经典的一道题,有许多种做法。

第一种:在挑战程序设计里面有介绍的分桶法。

第二种:以建立一棵线段树,每个节点维护当前区间的有序数组。

第三种:刚学的主席树,一棵普通的线段树在进行修改后是无法保存以前的线段树的,主席树的

作用就是把线段树更新前后的版本都保留下来。对于l 到 r 第 k 大的, 我们只要比较r插入后的

线段树版本和 l 插进来之前的线段树版本,就能找到第k大的数。

技术分享
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<vector>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=1e5+5;
 7 struct node
 8 {
 9     int l,r,sum;
10 } seg[N*40];
11 vector<int> v;
12 int a[N],n,q,x,y,k,root[N],cnt;//root[i],表示插入第i数之后版本的树根。
13 int get_id(int x){ return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}//二分查离散后的序号
14 void update(int l,int r,int &x,int y,int pos)//注意x用引用,这样边进行递归,边给节点的父亲赋值。
15 {
16     seg[++cnt]=seg[y]; seg[cnt].sum++; x=cnt;
17     if(l==r) return;
18     int m=(l+r)>>1;
19     if(m>=pos) update(l,m,seg[x].l,seg[y].l,pos);
20     else update(m+1,r,seg[x].r,seg[y].r,pos);
21 }
22 int query(int l,int r,int x,int y,int k)
23 {
24     if(l==r) return l;
25     int res=0,m=(l+r)>>1;
26     res+=seg[seg[y].l].sum-seg[seg[x].l].sum;// 这是x和y 两个版本之间从l 到 m数量的差值。
27     if(res>=k) return query(l,m,seg[x].l,seg[y].l,k); //如果差值大于等于k,说明第k个数在l 到 m之间
28     else return query(m+1,r,seg[x].r,seg[y].r,k-res);
29 }
30 int main()
31 {
32     scanf("%d%d",&n,&q);
33     for(int i=1;i<=n;i++) scanf("%d",&a[i]),v.push_back(a[i]);
34     sort(v.begin(),v.end()); v.erase(unique(v.begin(),v.end()),v.end());//将数组里的数排序,去重进行离散化。
35     for(int i=1;i<=n;i++) update(1,n,root[i],root[i-1],get_id(a[i]));
36     for(int i=1;i<=q;i++)
37     {
38         scanf("%d%d%d",&x,&y,&k);
39         printf("%d\n",v[query(1,n,root[x-1],root[y],k)-1]);
40     }
41     return 0;
42 }
View Code

 

以上是关于POJ - 2104 K-th Number的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2104 K-th Number(分块+二分)

poj[2104]K-th Number

[POJ 2104]K-th Number

[POJ 2104]K-th Number

poj2104K-th Number

poj2104K-th Number (主席树)