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