K - K-th Number
POJ - 2104
You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment.
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.
Inputnode
The first line of the input file contains n --- the size of the array, and m --- the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000).
The second line contains n different integer numbers not exceeding 109 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).
Outputios
For each question output the answer to it --- the k-th number in sorted a[i...j] segment.
Sample Input数组
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3
Sample Outputide
5
6
3
Hint函数
This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.
题意:给你一个数组,告诉你若干个区间和k,让你求出在这个区间里升序排第k的数。
注意:
这题是主席树裸的板子题,通常给你的空间上限是1e5或者常数级倍数由于数据量要开20倍。通常都须要进行离散化。只根据板子来的话主要操做为4步,详细在main函数的注释里。ui
板子一:this
#include <string.h> #include <algorithm> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <deque> #include <fstream> #include <iomanip> #include <iostream> #include <iterator> #include <list> #include <map> #include <queue> #include <set> #include <stack> #include <stdexcept> #include <string> #include <vector> using namespace std; typedef unsigned long long ull; #define ll long long #define int long long const int maxn = 1e5 + 10; const int inf = 0x3f3f3f3f; const int Base = 131; const ll INF = 1ll << 62; // const double PI = acos(-1); const double eps = 1e-7; const int mod = 999; #define mem(a, b) memset(a, b, sizeof(a)) #define speed \ { \ ios::sync_with_stdio(false); \ cin.tie(0); \ cout.tie(0); \ } // inline int gcd(int a, int b) { // while (b ^= a ^= b ^= a %= b); // return a; // } inline ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); } long long fastPower(long long base, long long power) { long long result = 1; while (power > 0) { if (power & 1) result = result * base % mod; power >>= 1; base = (base * base) % mod; } return result; } inline ll rd() { ll s = 0, w = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') w = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar(); return s * w; } int a[maxn]; int rt[maxn]; //rt[i]表示由数组前i个元素组成的线段树的根结点 struct node { int l, r; //线段树左右子结点点 int sum; //结点信息,表示这颗子树存在的元素的数目 } T[maxn * 20]; int tot = 0; //结点编号 vector<int> v; int getid(int k) { return lower_bound(v.begin(), v.end(), k) - v.begin() + 1; } void build(int &o, int l, int r) //创建一颗空树 { o = ++tot; T[o].sum = 0; if (l == r) return; int mid = (l + r) / 2; build(T[o].l, l, mid); build(T[o].r, mid + 1, r); } void update(int l, int r, int &now, int last, int k) { T[++tot] = T[last]; //复制线段树(加入新的点) //更新当前线段树的根结点 now = tot; T[tot].sum++; if (l == r) //修改到叶子结点为止 return; //根据须要修改的k来肯定是修改左子树仍是修改右子树 int mid = (l + r) >> 1; if (k <= mid) update(l, mid, T[now].l, T[last].l, k); else update(mid + 1, r, T[now].r, T[last].r, k); } int query(int l, int r, int x, int y, int k) //查询区间【x,y】中第小的数 { if (l == r) return l; //查询到叶子结点为止 int mid = (l + r) >> 1; int cnt = T[T[y].l].sum - T[T[x].l].sum; //第y颗树比第x颗树在左子树上多的结点数 if (cnt >= k) //答案在左子树上 return query(l, mid, T[x].l, T[y].l, k); else return query(mid + 1, r, T[x].r, T[y].r, k - cnt); } signed main() { int n = rd(); int m = rd(); for (int i = 1; i <= n; i++) { a[i] = rd(); v.push_back(a[i]); } sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); // 1.进行离散化注意 build(rt[0], 1, n); //2.建树注意 for (int i = 1; i <= n; i++) //3.更新注意 update(1, n, rt[i], rt[i - 1], getid(a[i])); while (m--) { int l = rd(); int r = rd(); int k = rd(); //若是想要从大到小第k个那么能够令 k = (r - l + 1) - k + 1 printf("%lld\n", v[query(1, n, rt[l - 1], rt[r], k) - 1]); //4.输出注意 } system("pause"); return 0; }
板子二:spa
#include <list> #include <string.h> #include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <string> #include <cstring> #include <vector> #include <map> #include <deque> #include <stack> #include <queue> #include <set> #include <iomanip> #include <cstdlib> #include <stdexcept> #include <fstream> #include <iterator> using namespace std; typedef long long ll; //const int maxn = 1e5+10; const int inf = 0x3f3f3f3f; const ll INF = 1ll << 62; //const double PI = acos(-1); const double eps = 1e-7; const int mod = 998244353; #define speed \ { \ ios::sync_with_stdio(false); \ cin.tie(0); \ cout.tie(0); \ } using namespace std; const int MAXN = 1e5 + 5; typedef struct node { int x; int id; } node; int a[MAXN]; int ran[MAXN]; int rt[MAXN * 20], ls[MAXN * 20], rs[MAXN * 20], tot, size; int sum[MAXN * 20]; void build(int &root, int l, int r) { root = ++tot; sum[root] = 0; if (l == r) return; int mid = (l + r) >> 1; build(ls[root], l, mid); build(rs[root], mid + 1, r); } void update(int &root, int l, int r, int last, int x) { root = ++tot; ls[root] = ls[last]; rs[root] = rs[last]; sum[root] = sum[last] + 1; if (l == r) return; int mid = (l + r) >> 1; if (mid >= x) update(ls[root], l, mid, ls[last], x); else update(rs[root], mid + 1, r, rs[last], x); } int query(int ss, int tt, int l, int r, int k) { if (l == r) return l; int cnt = sum[ls[tt]] - sum[ls[ss]]; int mid = (l + r) >> 1; if (k <= cnt) return query(ls[ss], ls[tt], l, mid, k); else return query(rs[ss], rs[tt], mid + 1, r, k - cnt); } int main() { int n, m; scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); ran[i] = a[i]; } tot = 0; sort(ran + 1, ran + n + 1); size = unique(ran + 1, ran + n + 1) - (ran + 1); build(rt[0], 1, size); for (int i = 1; i <= n; i++) a[i] = lower_bound(ran + 1, ran + 1 + size, a[i]) - ran; for (int i = 1; i <= n; i++) update(rt[i], 1, size, rt[i - 1], a[i]); while (m--) { int l, r, k; scanf("%d %d %d", &l, &r, &k); int id = query(rt[l - 1], rt[r], 1, size, k); //若是想要的是从大到小第k个能够令 id = (r - l + 1) - id + 1 printf("%d\n", ran[id]); } system("pause"); return 0; } /* 1 10 5 1 4 2 3 5 6 7 8 9 0 1 3 2 */