题目链接:http://poj.org/problem?id=2104
Description
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?"
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.
Input
The second line contains n different integer numbers not exceeding 10 9 by their absolute values --- the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).
Output
Sample Input
7 3 1 5 2 6 3 7 4 2 5 3 4 4 1 1 7 3
Sample Output
5 6 3
Hint
题意:
写一个数据结构,能够快速返回指定区间内的第k小元素。
即:数组a[1:n]包含n个不同的整数,Q(i,j,k)代表询问:“若a[i:j]中元素从小到大排列,则其中第k个元素是什么?”
例如:数组a = (1, 5, 2, 6, 3, 7, 4),现有查询Q(2, 5, 3),由于a[2:5]为(5, 2, 6, 3),升序排列后为(2, 3, 5, 6),第3个元素为5,所以Q(2, 5, 3) = 5
数据范围:
数组内元素个数n:1 ≤ n ≤ 100 000;
查询个数m:1 ≤ m ≤ 5 000;
元素大小:[-1e9,1e9];
对于询问Q(i,j,k):1 ≤ i ≤ j ≤ n, 1 ≤ k ≤ j - i + 1;
题解:
主席树参考:
https://www.bilibili.com/video/av4619406/
https://blog.csdn.net/regina8023/article/details/41910615
AC代码:
#include<cstdio> #include<algorithm> #include<vector> using namespace std; const int maxn=100000+5; //主席树 struct Node{ int l,r,sum; }node[maxn*40]; int root[maxn]; int cnt; void update(int l,int r,int x,int &y,int pos) { cnt++; node[cnt]=node[x]; node[cnt].sum++; y=cnt; if(l==r) return; int mid=(l+r)/2; if(mid>=pos) update(l,mid,node[x].l,node[y].l,pos); else update(mid+1,r,node[x].r,node[y].r,pos); } int query(int l,int r,int x,int y,int k) { if(l==r) return l; int mid=(l+r)/2; int sum=node[node[y].l].sum-node[node[x].l].sum; if(sum>=k) return query(l,mid,node[x].l,node[y].l,k); else return query(mid+1,r,node[x].r,node[y].r,k-sum); } //离散化 vector<int> v; inline int getID(int x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;} inline int getVal(int id){return v.at(id-1);} int a[maxn]; int main() { int n,q; scanf("%d%d",&n,&q); v.clear(); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); v.push_back(a[i]); } sort(v.begin(),v.end()); v.erase(unique(v.begin(),v.end()),v.end()); root[0]=0; node[0].l=node[0].r=0; node[0].sum=0; //初始化第0棵树 for(int i=1;i<=n;i++) update(1,n,root[i-1],root[i],getID(a[i])); //构建第1~n棵树 for(int i=1;i<=q;i++) { int l,r,k; scanf("%d%d%d",&l,&r,&k); printf("%d\n",getVal(query(1,n,root[l-1],root[r],k))); } }
注:
vector容器的方法:
unique函数:
unique(st,ed) 对[st,ed)区间的数据进行去重。
功能:对有序的容器重新排列,将所有第一次出现的元素从前往后排,所有重复出现的元素依次排在后面。
返回值:返回迭代器,迭代器指向的是重复元素的首地址。
lower_bound(st,ed,x) 在有序的序列中,返回[st,ed)区间内第一个不小于x的元素的位置。
upper_bound(st,ed,x) 在有序的序列中,返回[st,ed)区间内第一个大于x的元素的位置。