思路:
首先对于单个查询(k, p)来说,答案一定是a数组中的前k大数。如果第k大的数字有多个怎么办?取索引最小的若干个。所以我们只需对a数组按照值降序,索引升序排序即可。
多个查询怎么办?离线处理。依然是对数组a按照上面的方法排序,然后对所有的查询按照k升序排序,分别离线计算。具体做法是,按顺序扫描a,用一个集合动态维护前k大的数,当发现某个查询正好询问前k大时,即时处理即可。
那么如何从一个集合中快速找到第k大数?c++标准库中原始的set是不行的,可以用1. 二分+树状数组(或线段树)2. __gnu_pbds https://www.geeksforgeeks.org/ordered-set-gnu-c-pbds/
实现1(二分+树状数组,n * log(n) * log(n)):
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 const int MAXN = 200000; 5 typedef pair<int, int> pii; 6 7 int a[MAXN + 5], bit[MAXN + 5]; 8 9 int lowbit(int x) { return x & -x; } 10 11 void add(int i, int x) 12 { 13 while (i <= MAXN) { bit[i] += x; i += lowbit(i); } 14 } 15 16 int sum(int i) 17 { 18 int ans = 0; 19 while (i) { ans += bit[i]; i -= lowbit(i); } 20 return ans; 21 } 22 23 bool cmp(pii& a, pii& b) 24 { 25 if (a.first != b.first) return a.first > b.first; 26 return a.second < b.second; 27 } 28 29 void work(pii& q, map<pii, int>& mp) 30 { 31 int k = q.first, p = q.second; 32 int l = 1, r = MAXN, res = -1; 33 while (l <= r) 34 { 35 int m = l + r >> 1; 36 if (sum(m) < p) l = m + 1; 37 else { res = m; r = m - 1; } 38 } 39 assert(res != -1); 40 mp[q] = res; 41 } 42 43 int main() 44 { 45 ios::sync_with_stdio(false); 46 int n, m; 47 while (cin >> n) 48 { 49 memset(bit, 0, sizeof bit); 50 vector<int> a(n); 51 for (int i = 0; i < n; i++) cin >> a[i]; 52 vector<pii> b(n); 53 for (int i = 0; i < n; i++) { b[i].first = a[i]; b[i].second = i + 1; } 54 sort(b.begin(), b.end(), cmp); 55 cin >> m; 56 vector<pii> q(m); 57 for (int i = 0; i < m; i++) cin >> q[i].first >> q[i].second; 58 vector<pii> sorted_q(q.begin(), q.end()); 59 sort(sorted_q.begin(), sorted_q.end()); 60 map<pii, int> res; 61 int cur = 0; 62 for (int i = 0; i < n; i++) 63 { 64 add(b[i].second, 1); 65 while (cur < m && i + 1 == sorted_q[cur].first) 66 { 67 work(sorted_q[cur], res); 68 cur++; 69 } 70 } 71 for (auto it: q) 72 { 73 int id = res[it]; 74 cout << a[id - 1] << endl; 75 } 76 } 77 return 0; 78 }
实现2(__gnu_pbds,n * log(n)):
1 #include <bits/stdc++.h> 2 3 #include <ext/pb_ds/assoc_container.hpp> 4 #include <ext/pb_ds/tree_policy.hpp> 5 6 using namespace std; 7 using namespace __gnu_pbds; 8 9 typedef pair<int, int> pii; 10 typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set; 11 12 bool cmp(pii& a, pii& b) 13 { 14 if (a.first != b.first) return a.first > b.first; 15 return a.second < b.second; 16 } 17 18 int main() 19 { 20 ios::sync_with_stdio(false); 21 int n, m; 22 while (cin >> n) 23 { 24 vector<int> a(n); 25 for (int i = 0; i < n; i++) cin >> a[i]; 26 vector<pii> b(n); 27 for (int i = 0; i < n; i++) { b[i].first = a[i]; b[i].second = i + 1; } 28 sort(b.begin(), b.end(), cmp); 29 cin >> m; 30 vector<pii> q(m); 31 for (int i = 0; i < m; i++) cin >> q[i].first >> q[i].second; 32 vector<pii> sorted_q(q.begin(), q.end()); 33 sort(sorted_q.begin(), sorted_q.end()); 34 map<pii, int> res; 35 int cur = 0; 36 ordered_set st; 37 for (int i = 0; i < n; i++) 38 { 39 st.insert(b[i].second); 40 while (cur < m && i + 1 == sorted_q[cur].first) 41 { 42 res[sorted_q[cur]] = *st.find_by_order(sorted_q[cur].second - 1); 43 cur++; 44 } 45 } 46 for (auto it: q) 47 { 48 cout << a[res[it] - 1] << endl; 49 } 50 } 51 }