Before learning the Chairman of the tree without modification, and today I want to learn about the Chairman of the tree to be modified. Prior to revisit this tree a bit Chairman, President tree has a new understanding.
Chairman of the tree is actually a historical record of every version of the tree, so this space to open a large, usually open 40 times is enough.
First, to build an empty tree, then we ask for the number of discretization, the last is updated each time a new tree.
void build(int &id,int l,int r) { id = ++tot; sum[id] = 0; int mid = (l + r) >> 1; if (l == r) return; build(lc[id], l, mid); build(rc[id], mid + 1, r); }
During each new achievements in the sum ++ this is well understood, because we put a point into it, so the new trees after inheriting the original information to +1
The weights on the line and a bit like a tree. This is an update operation
Update int (ID int, int L, R & lt int, int Val) { int TOT RT = ++; SUM [RT] = SUM [ID] +. 1; LC [RT] = LC [ID], RC [RT] = RC [ID]; IF (R & lt == L) return RT; int MID = (L + R & lt) >>. 1; IF (Val <= MID) LC [RT] = Update (LC [RT], L, MID, val); // if we want to put this number is smaller than the mid, go out into the small side update else rc [rt] = update ( rc [rt], mid + 1, r, val); // to the contrary is a big update here. RT return; }
I think it is more difficult to write the query
int query (int u, int v , int l, int r, int k) // u is the first segment, v is the second segment { int MID = (L + R & lt) >>. 1; int X = SUM [lc [u]] - sum [lc [v]]; // sum subtraction represents the number inside this interval if (l == r) return l ; // l == r if it reaches a leaf node Description found if (k <= x) return query (lc [u], lc [v], l, mid, k); // if a small number of large k than the left section, then the interval left return query (rc [u], rc [ v], mid + 1, r, k - x); // if in the right range, then it should be left by subtracting the number of sections } // this sum is in fact stored number, we seek to find the k-th largest in fact, what this period is the interval of the k-number, if in the right range, then it should be the right section of the k-sum [] large
This topic Link to K-th Number
Overall Code
#include <cstdio> #include <cstdlib> #include <cstring> #include <queue> #include <vector> #include <string> #include <algorithm> #include <iostream> #include <map> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int maxn = 1e5 + 10; int root[maxn * 40], lc[maxn * 40], rc[maxn * 40], sum[maxn * 40]; int tot = 0; void build(int &id,int l,int r) { id = ++tot; sum[id] = 0; int mid = (l + r) >> 1; if (l == r) return; build(lc[id], l, mid); build(rc[id], mid + 1, r); } int update(int id,int l,intR & lt, int Val) { int RT = ++ TOT; SUM [RT] = SUM [ID] + . 1 ; LC [RT] = LC [ID], RC [RT] = RC [ID]; IF (L == R & lt) return RT; int MID = (L + R & lt) >> . 1 ; IF (Val <= MID) LC [RT] = Update (LC [RT], L, MID, Val); // if we want to put in this mid smaller than this number, go out into the small side updates the else RC [RT] = update (RC [RT], mid + . 1 , R & lt, Val); // contrary is updated to the larger side. return RT; } int Query ( int U, intV, int L, int R & lt, int K) // U is the first segment, v is the second segment { int MID = (L + R & lt) >> . 1 ; int X = SUM [LC [U]] - SUM [LC [V]]; // SUM subtraction inside this interval represents the number of IF (l == r) return L; // if l == r to reach a leaf node found described IF (K <= X) return Query (LC [U], LC [V], L, MID, k); // if a large number of the k-th small interval than the left, then left section return Query (RC [U], RC [V], + MID . 1 , R & lt, K - X); // if the number in the right section, should then be subtracted left section } //This sum is the amount actually exist, we seek to find the k-th largest in fact, what this period the number of k-interval is, if in the right range, then it should be the right section of the k-sum [] big int A [MAXN] , B [MAXN]; int main () { int n-, m; Scanf ( " % D% D " , & n-, & m); for ( int I = . 1 ; I <= n-; I ++) Scanf ( " % D " , & A [I]), B [I] = A [I]; Sort (B + . 1 , B + . 1 + n-); int len = UNIQUE (B + . 1 , B + . 1 + n-) - B - . 1 ; Build (the root [ 0 ],1, len); for (int i = 1; i <= n; i++) { a[i] = lower_bound(b + 1, b + 1 + len, a[i]) - b; root[i] = update(root[i - 1], 1, len, a[i]); } while (m--) { int l, r, k; scanf("%d%d%d", &l, &r, &k); int ans = query(root[r], root[l - 1], 1, len, k); printf("%d\n", b[ans]); } return 0; }