例题:POJ-2104
求区间第k大
sum代表当前数是第几大
对每个数建一棵树
当前树的sum 继承自上一颗树的sum 从祖先到当前数的位置 sum++
如果前面的数中没有比当前数大的数 sum++后为1 即为第一大的数
而其它小的数的sum在从祖先到当前数的位置寻找时顺便sum++更新
#include <iostream> #include <cstdio> #include <vector> #include <cstring> #include <algorithm> #include <cmath> #define mem(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn = 1e5 + 6, INF = 0x7fffffff; int n, m, cnt, root[maxn], a[maxn], x, y, k; struct node{int l, r, sum;}T[maxn*40]; vector<int> v; int getid(int x){return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;} void update(int l, int r, int& x, int y, int pos) { T[++cnt] = T[y], T[cnt].sum++, x = cnt; if(l == r) return; int mid = (l + r) / 2; if(mid >= pos) return update(l, mid, T[x].l, T[y].l, pos); else return update(mid+1, r, T[x].r, T[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 = T[T[y].l].sum - T[T[x].l].sum; if(sum >= 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 - sum); } int main() { scanf("%d%d", &n, &m); 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()); for(int i=1; i<=n; i++) update(1, n, root[i], root[i-1], getid(a[i])); for(int i=1; i<=m; i++) { scanf("%d%d%d", &x, &y, &k); printf("%d ", v[query(1, n, root[x-1], root[y], k) - 1]); } return 0; }