主席树板子题
K - K-th Number
POJ - 2104You 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.
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 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).
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).
Output
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 Output
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函数的注释里。
板子一:
#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; }
板子二:
#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 */

浙公网安备 33010602011771号