求区间第k小,划分树,又一种神奇的数据结构。2104也可以用这个代码AC,那道题是裸的求第k小。
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<algorithm> using namespace std; const int MAXN = 100010; struct Node { int l, r; }T[MAXN << 2]; int d[MAXN], s[MAXN], t[21][MAXN], tol[21][MAXN]; void build(int level, int rt, int l, int r) { int i; T[rt].l = l, T[rt].r = r; if(l == r) return; int mid = l + r >> 1; int lsame = mid - l + 1; for(i = l; i <= r; i ++) { if(t[level][i] < s[mid]) lsame --; } int Ll = l, Lr = mid, Rl = mid + 1, Rr = r; int Ltot = 0, Rtot = 0; for(i = l; i <= r; i ++) { if(i == l) tol[level][i] = 0; else tol[level][i] = tol[level][i - 1]; if(t[level][i] < s[mid]) { tol[level][i] ++; t[level + 1][Ll + Ltot ++] = t[level][i]; } else if(t[level][i] > s[mid]) { t[level + 1][Rl + Rtot ++] = t[level][i]; } else { if(lsame > 0) { lsame --; t[level + 1][Ll + Ltot ++] = t[level][i]; tol[level][i] ++; } else { t[level + 1][Rl + Rtot ++] = t[level][i]; } } } build(level + 1, rt << 1, Ll, Lr); build(level + 1, rt << 1 | 1, Rl, Rr); } int query(int level, int rt, int l, int r, int k) { if(l == r) return t[level][l]; int nl, nls; if(l == T[rt].l) nls = 0; else nls = tol[level][l - 1]; nl = tol[level][r] - nls; if(nl >= k) { return query(level + 1, rt << 1, T[rt].l + nls, T[rt].l + nl + nls - 1, k); } else { int mid = (T[rt].l + T[rt].r) >> 1; int nre = l - T[rt].l + 1 - nls; int nr = r - l + 1 - nl; return query(level + 1, rt << 1 | 1, mid + nre, mid + nr + nre - 1, k - nl); } } int main() { int n, m, i; while(scanf("%d%d", &n, &m) == 2) { for(i = 1; i <= n; i ++) { scanf("%d", &d[i]); t[1][i] = s[i] = d[i]; } sort(s + 1, s + n + 1); build(1, 1, 1, n); int l, r, k; while(m --) { scanf("%d%d%d", &l, &r, &k); printf("%d\n", query(1, 1, l, r, k)); } } return 0; }