划分树算法 模板
2017-04-20 00:22
381 查看
转:http://www.cnblogs.com/pony1993/archive/2012/07/17/2594544.html
划分树是一种基于线段树的数据结构。主要用于快速求出(在log(n)的时间复杂度内)序列区间的第k大值 。
划分树和归并树都是用线段树作为辅助的,原理是基于快排 和归并排序 的。
划分树的建树过程基本就是模拟快排过程,取一个已经排过序的区间中值,然后把小于中值的点放左边,大于的放右边。并且记录d层第i个数之前(包括i)小于中值的放在左边的数。具体看下面代码注释。
模板
划分树是一种基于线段树的数据结构。主要用于快速求出(在log(n)的时间复杂度内)序列区间的第k大值 。
划分树和归并树都是用线段树作为辅助的,原理是基于快排 和归并排序 的。
划分树的建树过程基本就是模拟快排过程,取一个已经排过序的区间中值,然后把小于中值的点放左边,大于的放右边。并且记录d层第i个数之前(包括i)小于中值的放在左边的数。具体看下面代码注释。
模板
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define MAX_SIZE 100005 int sorted[MAX_SIZE];//已经排好序的数据 int toleft[25][MAX_SIZE]; int tree[25][MAX_SIZE]; void build_tree(int left, int right, int deep) { int i; if (left == right) return ; int mid = (left + right) >> 1; int same = mid - left + 1; //位于左子树的数据 for (i = left; i <= right; ++i) {//计算放于左子树中与中位数相等的数字个数 if (tree[deep][i] < sorted[mid]) { --same; } } int ls = left; int rs = mid + 1; for (i = left; i <= right; ++i) { int flag = 0; if ((tree[deep][i] < sorted[mid]) || (tree[deep][i] == sorted[mid] && same > 0)) { flag = 1; tree[deep + 1][ls++] = tree[deep][i]; if (tree[deep][i] == sorted[mid]) same--; } else { tree[deep + 1][rs++] = tree[deep][i]; } toleft[deep][i] = toleft[deep][i - 1]+flag; } build_tree(left, mid, deep + 1); build_tree(mid + 1, right, deep + 1); } int query(int left, int right, int k, int L, int R, int deep) { if (left == right) return tree[deep][left]; int mid = (L + R) >> 1; int x = toleft[deep][left - 1] - toleft[deep][L - 1];//位于left左边的放于左子树中的数字个数 int y = toleft[deep][right] - toleft[deep][L - 1];//到right为止位于左子树的个数 int ry = right - L - y;//到right右边为止位于右子树的数字个数 int cnt = y - x;//[left,right]区间内放到左子树中的个数 int rx = left - L - x;//left左边放在右子树中的数字个数 f398 if (cnt >= k) { //printf("sss %d %d %d\n", xx++, x, y); return query(L + x, L + y - 1, k, L, mid, deep + 1); // 因为x不在区间内 所以没关系 所以先除去,从L+x开始,然后确定范围 } else { //printf("qqq %d %d %d\n", xx++, x, y); return query(mid + rx + 1, mid + 1 + ry, k - cnt, mid + 1, R, deep + 1); //同理 把不在区间内的 分到右子树的元素数目排除,确定范围 } } int main() { int m, n; int a, b, k; int i; while (scanf("%d%d", &m, &n) == 2) { for (i = 1; i <= m; ++i) { scanf("%d", &sorted[i]); tree[0][i] = sorted[i]; } sort(sorted + 1, sorted + 1 + m); build_tree(1, m, 0); for (i = 0; i < n; ++i) { scanf("%d%d%d", &a, &b, &k); printf("%d\n", query(a, b, k, 1, m, 0)); } } return 0; }
相关文章推荐
- 【图像配准】基于灰度的模板匹配算法(三):划分强度一致法(PIU)
- 基于灰度的模板匹配算法(三):划分强度一致法(PIU)
- Graham 扫描算法求凸包,poj 2187(水题但是是我的第一个求n点集凸包模板)
- [模板]二分图算法-Hopcroft-Carp
- HDU 2063 过山车(匈牙利算法模板)
- 【网络流之最大流算法模板】HDUOJ 3549 Flow Problem
- 二分图最大匹配算法模板
- poj 1274 The Perfect Stall(匈牙利算法模板)
- 基于灰度的模板匹配算法:MAD、SAD、SSD、MSD、NCC、SSDA算法
- BZOJ - 2038: 小Z的袜子(hose) 莫队算法 模板
- 归并算法实现求解逆序对【模板】
- 监督学习-logistics回归算法模板
- SPEA算法模板
- 快速幂取模算法【模板】
- 模板匹配算法简介
- 畅联通工程续(最短路 算法模板。。。)
- Meisell-Lehmer算法(大素数模板)
- BZOJ 2140 浅谈 Tarjan 算法及模板
- java划分算法
- bzoj1770-------(算法模板系列之gauss消元异或方程组)