划分树是保存了快速排序的过程的树,可以用来求静态第k小的数

如果,划分树可以看做是线段树,它的左孩子保存了mid-L+1 个 小于等于 a[mid] 的数字,  右孩子保存了 R-mid个大于等于a[mid]的数字

数组a是排序过后的数组,而划分树保存的是原数组的数据,

划分树的构造就是将上一层[l,r]个数的 mid-l+1个数划分到左子区间,r-(mid-l+1)个数划分到了右子区间

void build(int l, int r, int rt)
{
if (l == r)
return;
int mid = (l + r) >> , isSame = mid - l + ;
for (int i = l; i <= r; ++i)
if (tree[rt][i] < sortA[mid])//mid-l+1个数被划入了左子树,减去比sortA[mid]小的,那么就是记录几个和其相等的被划入左子树
isSame--;
int lPos = l, rPos = mid + ;
for (int i = l; i <= r; ++i)
{
//sum[rt][i] 为前i个数字,有多少个数字被划分到了左区间
i == l ? sum[rt][i] = : sum[rt][i] = sum[rt][i - ];
if (tree[rt][i] < sortA[mid])
{
sum[rt][i]++;
tree[rt+][lPos++] = tree[rt][i];
}
else if (tree[rt][i]>sortA[mid])
{
tree[rt + ][rPos++] = tree[rt][i];
}
else
{
if (isSame > )
{
isSame--;
sum[rt][i]++;
tree[rt + ][lPos++] = tree[rt][i];
}
else
{
tree[rt + ][rPos++] = tree[rt][i];
}
}
}
build(l, mid, rt + );
build(mid + , r, rt + );
}

那么查询区间[l,r]第k大, 就是如果 sum[rt][r] - sum[rt][l-1] 如果>=k, 说明该区间有sum[rt][r] - sum[rt][l-1] 个数被划分到了左子区间,

所以应该去左区间找第k小的数, 否则,去右子区间找第k -( sum[rt][r] - sum[rt][l-1] ) 大的数

int query(int l, int r, int rt, int L, int R, int k)
{
int mid = (l + r) >> ;
if (l == r)
return tree[rt][l];
int s1, s2;
if (l == L)
{
s1 = ;
s2 = sum[rt][R];
}
else
{
s1 = sum[rt][L - ];
s2 = sum[rt][R] - s1;
}
//要记住查询的区间,同样也变化了
if (k<=s2)
return query(l, mid, rt + , l + s1, l + s1 + s2 - , k);
else
return query(mid + , r, rt + , mid + L - l + - s1, mid - l + - s1 + R - s2 ,k-s2);
}

poj2104

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int INF = <<;
/* */
const int N = + ;
int a[N], sortA[N], tree[][N],sum[][N]; void build(int l, int r, int rt)
{
if (l == r)
return;
int mid = (l + r) >> , isSame = mid - l + ;
for (int i = l; i <= r; ++i)
if (tree[rt][i] < sortA[mid])//mid-l+1个数被划入了左子树,减去比sortA[mid]小的,那么就是记录几个和其相等的被划入左子树
isSame--;
int lPos = l, rPos = mid + ;
for (int i = l; i <= r; ++i)
{
//sum[rt][i] 为前i个数字,有多少个数字被划分到了左区间
i == l ? sum[rt][i] = : sum[rt][i] = sum[rt][i - ];
if (tree[rt][i] < sortA[mid])
{
sum[rt][i]++;
tree[rt+][lPos++] = tree[rt][i];
}
else if (tree[rt][i]>sortA[mid])
{
tree[rt + ][rPos++] = tree[rt][i];
}
else
{
if (isSame > )
{
isSame--;
sum[rt][i]++;
tree[rt + ][lPos++] = tree[rt][i];
}
else
{
tree[rt + ][rPos++] = tree[rt][i];
}
}
}
build(l, mid, rt + );
build(mid + , r, rt + );
} int query(int l, int r, int rt, int L, int R, int k)
{
int mid = (l + r) >> ;
if (l == r)
return tree[rt][l];
int s1, s2;
if (l == L)
{
s1 = ;
s2 = sum[rt][R];
}
else
{
s1 = sum[rt][L - ];
s2 = sum[rt][R] - s1;
}
//要记住查询的区间,同样也变化了
if (k<=s2)
return query(l, mid, rt + , l + s1, l + s1 + s2 - , k);
else
return query(mid + , r, rt + , mid + L - l + - s1, mid - l + - s1 + R - s2 ,k-s2);
}
int main()
{
int n, m, k, L, R;
int t; while (scanf("%d%d", &n, &m)!=EOF)
{ for (int i = ; i <= n; ++i)
{
scanf("%d", &a[i]);
tree[][i] = sortA[i] = a[i];
}
sort(sortA, sortA + n + );
build(, n, );
while (m--)
{
scanf("%d%d%d", &L, &R, &k);
printf("%d\n", query(, n, , L, R, k));
}
}
return ;
}

划分树 静态第k大的更多相关文章

  1. POJ 2104:K-th Number(主席树静态区间k大)

    题目大意:对于一个序列,每次询问区间[l,r]的第k大树. 分析: 主席树模板题 program kthtree; type point=record l,r,s:longint; end; var ...

  2. 主席树(可持久化线段树) 静态第k大

    可持久化数据结构介绍 可持久化数据结构是保存数据结构修改的每一个历史版本,新版本与旧版本相比,修改了某个区域,但是大多数的区域是没有改变的, 所以可以将新版本相对于旧版本未修改的区域指向旧版本的该区域 ...

  3. HDU 4417 (划分树+区间小于k统计)

    题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4417 题目大意:给定一个区间,以及一个k值,求该区间内小于等于k值的数的个数.注意区间是从0开始的 ...

  4. HDU 3078 (LCA+树链第K大)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3078 题目大意:定点修改.查询树中任意一条树链上,第K大值. 解题思路: 先用离线Tarjan把每个 ...

  5. PAT天梯赛练习题 L3-002. 堆栈(线段树查询第K大值或主席树)

    L3-002. 堆栈 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 大家都知道“堆栈”是一种“先进后出”的线性结构,基本操作有 ...

  6. POJ 2104 K-th Number 主席树(区间第k大)

    题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...

  7. zoj2112 主席树动态第k大 (主席树&&树状数组)

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

  8. 主席树区间第K大

    主席树的实质其实还是一颗线段树, 然后每一次修改都通过上一次的线段树,来添加新边,使得每次改变就改变logn个节点,很多节点重复利用,达到节省空间的目的. 1.不带修改的区间第K大. HDU-2665 ...

  9. Splay树求第k大模板

    今天上午借着休息日得机会手撸了一下模板,终于对着模板调出来了.prev和next占用了std namespace里面的东西,然后报警我上次给关了所以.....就花了3个小时吧. inline加不加无所 ...

随机推荐

  1. cocos2d-x lua 内存回收

    使用cocos2d-x lua架构,游戏中存在两种内存回收方式. 1.cocos2d-x 本身内存回收 PS:假设在lua在创建一个类,继承cocos2d-x的一个类A,则该A也遵循cocos2d-x ...

  2. _00024 尼娜抹微笑伊拉克_云计算ClouderaManager以及CHD5.1.0群集部署安装文档V1.0

    笔者博文:妳那伊抹微笑 itdog8 地址链接 : http://www.itdog8.com(个人链接) 博客地址:http://blog.csdn.net/u012185296 博文标题:_000 ...

  3. 我们熟悉的Textbox

    创建只读文本框 方法一: 可用Readonly属性防止用户编辑文本框内容.将Readonly属性设置为True后,用户就可以滚动文本框中的文本并将其突出显示,但不能作任何更改.将Readonly属性设 ...

  4. go iota

    package main import ( "fmt" ) const ( a = 'A' b c = iota d ) func main() { fmt.Println(a) ...

  5. Android Studio之同一窗口打开项目

    Android Studio默认新打开的项目都是重新打开一个窗口,和原项目窗口同时存在,如果打开多个项目,则有很多窗口同时打开,怎么根据需要决定自己以何种方式打开呢? 1.设置打开新项目的方式 第一项 ...

  6. linux cent os putty 问题彻底解决办法

    出现乱码的根本原因: linux系统和putty使用的编码格式不一致. 解决办法: 1.首先使用命令查看linux当前使用的是什么编码格式 echo $LANG 返回的结果有如下几种情况:1)zh_C ...

  7. Binders 与 Window Tokens(窗体令牌)

    原文地址:http://www.androiddesignpatterns.com/2013/07/binders-window-tokens.html 安卓的一项核心设计思想是希望能提供一个不须要依 ...

  8. [Android]Volley源代码分析(店)应用

    通过前面的谈话,我相信你有Volley有了一定的了解了原理.本章将给出一些我们的应用程序都可以在样品中直接使用,第一样品是 NetworkImageView类,事实上NetworkImageView顾 ...

  9. c++windows内核编程笔记day12 硬盘逻辑分区管理、文件管理、内存管理

    windows系统磁盘文件存储: 分区格式:NTFS / FAT32 GetSystemDirectory();//获取系统路径 GetWindowsDirectory();//获取windows路径 ...

  10. EA强大功能之代码凝视

    前面讲了EA怎样方便我们生成代码,这次讲一下,怎样生成具体的凝视. 1.文件表头凝视 (1)点击工具----选项 在常规项里改动作者: 在代码project中改动代码project的默认语言. (2) ...