//poj 2104 K-th Number //划分树 //建树和查找,模板题,具体看代码 #define infile freopen("in.txt", "r", stdin); #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 100005 int ans; int level[20][N], sorted[N], l_cnt[20][N]; void build(int l, int r, int loc, int dep) { if(l == r) return; int mid = l + (r-l)/2; int mid_val = sorted[mid]; int cnt = 0; //记录小于mid_val的个数 for(int i = l; i <= r; ++i) if(level[dep][i] < mid_val) cnt++; //这里l_tot是从l开始···equal_cnt记录跟mid_val相等且进入左子树的个数 int l_tot = l, r_tot = mid+1, equal_cnt = 0; for(int i = l; i <= r; ++i) { if(level[dep][i] < mid_val) //小于mid_val的进入左子树 level[dep+1][l_tot++] = level[dep][i]; else if(level[dep][i] == mid_val && mid-l+1-cnt > equal_cnt) { //等于mid_val的且没超过左子树限定个数的时候进入左子树 equal_cnt++; level[dep+1][l_tot++] = level[dep][i]; } else level[dep+1][r_tot++] = level[dep][i]; l_cnt[dep][i] = l_tot - l;//记录进入左子树的个数 } build(l, mid, loc*2, dep+1); build(mid+1, r, loc*2+1, dep+1); } void find(int l, int r, int from, int to, int k, int dep) { if(l == r) { ans = level[dep][l]; return; } int mid = l + (r-l)/2; int from_cnt; //记录当前层中,from以前的数进入左子树的个数 if(from > 1) //不包括from from_cnt = l_cnt[dep][l+from - 2]; else from_cnt = 0; //记录当前层中,to以前的数进入又子树的个数,包括to int to_cnt = l_cnt[dep][l+to - 1]; //接下去那层就应该保持和这层一样的起点,即from左边的个数不变 //若下一层到左子树,则要从from以左的进入左子树的个数(from_cnt)开始 //由于from这个数也到左子树所以下一层应从from_cnt+1开始 //若下一层到右子树要去掉进入左子树的个数 if(to_cnt - from_cnt >= k) //from到to之间进入左子树的个数 find(l, mid, from_cnt+1, to_cnt, k, dep+1); else find(mid+1, r, from-from_cnt, to-to_cnt, k-(to_cnt-from_cnt), dep+1); } int main(void) { //infile int n, n_query; while(scanf("%d%d", &n, &n_query) != EOF) { for(int i = 1; i <= n; ++i) { scanf("%d", &level[1][i]); sorted[i] = level[1][i]; } sort(sorted+1, sorted+n+1); build(1, n, 1, 1); while(n_query--) { int from, to, k; scanf("%d%d%d", &from, &to, &k); find(1, n, from, to, k, 1); printf("%d\n", ans); } } return 0; }
还不懂的话可以看看这个
http://www.cnblogs.com/pony1993/archive/2012/07/17/2594544.html