hdu 4251 The Famous ICPC Team Again
hdu 4251 The Famous ICPC Team Again 划分树
//hdu 4251 The Famous ICPC Team Again //划分树 //求中位数(就是求中间大的) //建树和查找,模板题,看代码 //不懂可以看看这人写的 //http://www.cnblogs.com/183zyz/archive/2012/08/01/2618295.html #define infile freopen("in.txt", "r", stdin); #include <stdio.h> #include <string.h> #include <algorithm> #define N 100005 using namespace std; struct NODE { int l, r; }tree[4*N]; int sorted[N], level[20][N];//level记录每一层每个段的序列 int l_cnt[20][N]; //记录left到right中进入 void build(int left, int right, int loc, int dep) { tree[loc].l = left; tree[loc].r = right; if(left == right) return; int mid = left + (right-left)/2; int mid_val = sorted[mid]; int cnt = 0; //记录小于left到right这段的中值的个数 for(int i = left; i <= right; ++i) if(level[dep][i] < mid_val) cnt++; //这里l_tot是从left开始··· int l_tot = left, r_tot = mid + 1; int equal_cnt = 0; //equal_cnt记录跟mid_val相等且进入左子树的个数 for(int i = left; i <= right; ++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-left+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 - left; //记录进入左子树的个数 } build(left, mid, 2*loc, dep+1); build(mid+1, right, 2*loc+1, dep+1); } int ans; void find(int loc, int from, int to, int dep, int aim) { int left = tree[loc].l, right = tree[loc].r; if(left == right) { ans = level[dep][left]; return; } int mid = left + (right-left)/2; //l_from记录当前层中,from以前的数进入左子树的个数(不包括from这个数) //l_to记录当前层中,to以前的数进入又子树的个数,包括to int l_from, l_to = l_cnt[dep][left+to-1]; if(from > 1) l_from = l_cnt[dep][from+left-2]; else l_from = 0; //接下去那层就应该保持和这层一样的起点,即from左边的个数不变 //若下一层到左子树,则要从from以左的进入左子树的个数(from_cnt)开始 //由于from这个数也到左子树所以下一层应从from_cnt+1开始 //若下一层到右子树要去掉进入左子树的个数 if(l_to - l_from >= aim) //from到to之间进入左子树的个数 find(2*loc, l_from+1, l_to, dep+1, aim); else find(2*loc+1, from-1-l_from+1, to-l_to, dep+1, aim-(l_to-l_from)); } int main() { //infile int n, n_case = 1;; while(scanf("%d", &n) != EOF) { printf("Case %d:\n", n_case++); 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); int n_query; scanf("%d", &n_query); while(n_query--) { int from, to; scanf("%d%d", &from, &to); find(1, from, to, 1, (to-from)/2+1); printf("%d\n", ans); } } return 0; }