博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
poj2104 划分树 区间K大 在线 无修改
阅读量:4626 次
发布时间:2019-06-09

本文共 3413 字,大约阅读时间需要 11 分钟。

博主sbit。。。。对于高级数据结构深感无力,然后这些东西在OI竟然烂大街了,不搞就整个人都不好了呢。

于是我勇猛的跳进了这个大坑

          ——sbit

区间K大的裸题,在线,无修改。

可以用归并树(\(O(nlog^3n)\)),也可用划分树(\(O(nlogn + mlogn)\))。果断划分树。。。(以后再来看归并树。。。再来看。。。来看。。看。。)

划分树是个什么东西呢?为什么可以做区间k大呢?

想想平衡树做k大时是如何搞的,其实内在原理是一样的。

划分树分两个步骤:建树与询问。

1. 建树

  划分树借鉴了快排的思想。划分树的每个节点保存了一个区间,以此区间为根节点,把区间分为左子树[left, mid]和右子树[mid + 1, right]的两个子树,保证左子树内的的值不大于根节点中中位数的值,右子树不小于之,且数值在子树中的顺序遵从在根节点中时的相对位置关系。关键之处在于,给每个数值记录一个to_left,表示从[left, i]中,被划分到左子树的值的数量,在查询中,这将起到至关的作用。对于没有相同取中位数值的元素时,只要比对大小关系来进行划分即可,但是,如果有相同取中位数值的元素时,如何处理这些元素呢?

  method 1: 离散化。。简洁易懂,方便快捷。

  method 2: 这个方法很巧妙,网上大多数代码(都是抄hh的,sbit也是的,羞耻play了)都使用了这个方法。参考资料1给出了详细的解释。

  引用自参考资料1:

划分的时候还有一点需要处理:如果有多个数据相同怎么办呢?通过一种特殊的处理:尽量使左右两边平均分配相同的数。这个特殊处理是这样的:

在没分之前,先假设中位数左边的数据suppose都已经分到左边了,所以suppose=mid-left+1;然后如果真的分在左边,即if(tree[level][i]<sorted[mid])

suppose--;suppose就减一!到最后,如果suppos=1,则说明中位数左边的数都小于中位数,如果有等于中位数的,则suppose大于1。 

最后分配的时候,把suppose个数,分到左边就可以了,剩下的分到右边!因为suppose的初值是mid-left+1,这样就能保证中位数左边和右边的数平衡了!

2. 询问

  类似于平衡树求k大,利用上文求出来的to_left值,我们可以通过深入划分树的层级对k的值进行缩小,最后当区间长度等于1时,k等于1,答案只有一个——就是当前值啦!用纸画画就能明白了。

 

1 #include 
2 #include
3 using namespace std; 4 const int maxn = 100000 + 10; 5 int val[20][maxn], sorted[maxn], to_left[20][maxn]; 6 int n, m; 7 void build_tree(int l, int r, int layer) { 8 if(l == r) return ; 9 int mid = (l + r) >> 1;10 int suppose = mid - l + 1;11 for(int i = l; i <= r; ++i)12 if(val[layer][i] < sorted[mid])13 --suppose;14 int rec_l = l, rec_r = mid + 1;15 for(int i = l; i <= r; ++i) {16 if(i == l) {17 to_left[layer][i] = 0;18 } else {19 to_left[layer][i] = to_left[layer][i - 1];20 }21 if(val[layer][i] < sorted[mid]) {22 ++to_left[layer][i];23 val[layer + 1][rec_l++] = val[layer][i];24 } else if(val[layer][i] > sorted[mid]) {25 val[layer + 1][rec_r++] = val[layer][i];26 } else {27 if(suppose != 0) {28 --suppose;29 ++to_left[layer][i];30 val[layer + 1][rec_l++] = val[layer][i];31 } else {32 val[layer + 1][rec_r++] = val[layer][i];33 }34 }35 }36 build_tree(l, mid, layer + 1);37 build_tree(mid + 1, r, layer + 1);38 }39 40 int query(int l, int r, int layer, int ql, int qr, int kth) {41 if(l == r) return val[layer][l];42 int s, ss;43 if(l == ql) {44 s = 0;45 ss = to_left[layer][qr];46 } else {47 s = to_left[layer][ql - 1];48 ss = to_left[layer][qr] - s;49 }50 int mid = (l + r) >> 1;51 if(kth <= ss) {52 return query(l, mid, layer + 1, l + s, l + s + ss - 1, kth);53 }54 return query(mid + 1, r, layer + 1, mid + 1 + ql - s - l, mid + 1 + qr - l - s - ss, kth - ss);55 }56 57 int main() {58 #ifndef ONLINE_JUDGE59 freopen("data.in", "r", stdin); freopen("data.out", "w", stdout);60 #endif61 scanf("%d%d", &n, &m);62 for(int i = 1; i <= n; ++i) {63 scanf("%d", &sorted[i]);64 val[0][i] = sorted[i];65 }66 sort(sorted + 1, sorted + n + 1);67 build_tree(1, n, 0);68 while(m--) {69 int l, r, k;70 scanf("%d%d%d", &l, &r, &k);71 printf("%d\n", query(1, n, 0, l, r, k));72 }73 return 0;74 }
View Code

 

参考资料:

转载于:https://www.cnblogs.com/hzf-sbit/p/3889086.html

你可能感兴趣的文章
各地IT薪资待遇讨论
查看>>
splay入门
查看>>
带CookieContainer进行post
查看>>
C语言学习笔记--字符串
查看>>
关于七牛进行图片添加文字水印操作小计
查看>>
DataSource数据库的使用
查看>>
Luogu4069 SDOI2016 游戏 树链剖分、李超线段树
查看>>
Java的内部类真的那么难以理解?
查看>>
一文搞懂Java环境,轻松实现Hello World!
查看>>
hash实现锚点平滑滚动定位
查看>>
也谈智能手机游戏开发中的分辨率自适应问题
查看>>
关于 IOS 发布的点点滴滴记录(一)
查看>>
vue+element-ui实现表格checkbox单选
查看>>
[周记]8.7~8.16
查看>>
递归定义
查看>>
kindeditor 代码高亮设置
查看>>
图的邻接表存储
查看>>
2018 leetcode
查看>>
PHP中获取当前页面的完整URL
查看>>
Chapter 4 Syntax Analysis
查看>>