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

 

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

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

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

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

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

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

 

POJ - 2104    K-th Number_线段树POJ - 2104    K-th Number_整体二分_02
 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

 

还有一种整体二分的写法,整体二分是一种离线算法,对于只有一个询问的k小,我们可以二分答案,有m个询问,

如果对每个都进行二分肯定会有冗余,整体二分就是进行一次二分答案,就能得出所有结果。

 

POJ - 2104    K-th Number_线段树POJ - 2104    K-th Number_整体二分_02
  1 #include<cstdio>
  2 #include<algorithm>
  3 #define fi first
  4 #define se second
  5 #define pb push_back
  6 #define mk make_pair
  7 #define pii pair<int,int>
  8 #define read(x) scanf("%d",&x)
  9 #define lread(x) scanf("%lld",&x)
 10 using namespace std;
 11 
 12 typedef long long ll;
 13 const int N=2e5+7;
 14 const int mod=1e9+7;
 15 const int base=17;
 16 const int inf=0x3f3f3f3f;
 17 const ll INF=0x3f3f3f3f3f3f3f3f;
 18 
 19 int n,m,tot,ans[N];
 20 pii a[N];
 21 struct Qus
 22 {
 23     int l,r,k,cnt,id;
 24 }qus[N],tmp[N];
 25 struct BIT
 26 {
 27     int a[N];
 28     void modify(int x,int v)
 29     {
 30         for(int i=x;i<=n;i+=i&-i)
 31             a[i]+=v;
 32     }
 33     int sum(int x)
 34     {
 35         int ans=0;
 36         for(int i=x;i;i-=i&-i)
 37             ans+=a[i];
 38         return ans;
 39     }
 40 }bit;
 41 void cal(int l,int r,int down,int mid)
 42 {
 43     int pos=lower_bound(a+1,a+1+n,mk(down,0))-a;
 44     for(int i=pos;i<=n && a[i].fi<=mid;i++)
 45         bit.modify(a[i].se,1);
 46     for(int i=l;i<=r;i++)
 47         qus[i].cnt=bit.sum(qus[i].r)-bit.sum(qus[i].l-1);
 48     for(int i=pos;i<=n && a[i].fi<=mid;i++)
 49         bit.modify(a[i].se,-1);
 50 
 51 }
 52 void work(int l,int r,int down,int up)
 53 {
 54     if(down>up || l>r) return;
 55     if(down==up)
 56     {
 57         for(int i=l;i<=r;i++)
 58             ans[qus[i].id]=down;
 59         return;
 60     }
 61     int mid=(up+down)>>1;
 62     int item1=l,item2=r;
 63     cal(l,r,down,mid);
 64     for(int i=l;i<=r;i++)
 65     {
 66         if(qus[i].cnt>=qus[i].k)
 67             tmp[item1++]=qus[i];
 68         else
 69         {
 70             qus[i].k-=qus[i].cnt;
 71             tmp[item2--]=qus[i];
 72         }
 73     }
 74     for(int i=l;i<=r;i++)
 75         qus[i]=tmp[i];
 76     work(l,item1-1,down,mid);
 77     work(item2+1,r,mid+1,up);
 78 }
 79 int main()
 80 {
 81     int mx=-inf,mn=inf;
 82     read(n); read(m);
 83     for(int i=1;i<=n;i++)
 84     {
 85         read(a[i].fi),a[i].se=i;
 86         mx=max(mx,a[i].fi);
 87         mn=min(mn,a[i].fi);
 88     }
 89     sort(a+1,a+n+1);
 90     for(int i=1;i<=m;i++)
 91     {
 92         read(qus[i].l);
 93         read(qus[i].r);
 94         read(qus[i].k);
 95         qus[i].id=i;
 96     }
 97     work(1,m,mn,mx);
 98     for(int i=1;i<=m;i++)
 99         printf("%d\n",ans[i]);
100     return 0;
101 }
102 /*
103 */
View Code