划分树 静态第k大
划分树是保存了快速排序的过程的树,可以用来求静态第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);
}
#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大的更多相关文章
- POJ 2104:K-th Number(主席树静态区间k大)
题目大意:对于一个序列,每次询问区间[l,r]的第k大树. 分析: 主席树模板题 program kthtree; type point=record l,r,s:longint; end; var ...
- 主席树(可持久化线段树) 静态第k大
可持久化数据结构介绍 可持久化数据结构是保存数据结构修改的每一个历史版本,新版本与旧版本相比,修改了某个区域,但是大多数的区域是没有改变的, 所以可以将新版本相对于旧版本未修改的区域指向旧版本的该区域 ...
- HDU 4417 (划分树+区间小于k统计)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4417 题目大意:给定一个区间,以及一个k值,求该区间内小于等于k值的数的个数.注意区间是从0开始的 ...
- HDU 3078 (LCA+树链第K大)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3078 题目大意:定点修改.查询树中任意一条树链上,第K大值. 解题思路: 先用离线Tarjan把每个 ...
- PAT天梯赛练习题 L3-002. 堆栈(线段树查询第K大值或主席树)
L3-002. 堆栈 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 大家都知道“堆栈”是一种“先进后出”的线性结构,基本操作有 ...
- POJ 2104 K-th Number 主席树(区间第k大)
题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...
- zoj2112 主席树动态第k大 (主席树&&树状数组)
Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB The Company Dynamic Rankings has ...
- 主席树区间第K大
主席树的实质其实还是一颗线段树, 然后每一次修改都通过上一次的线段树,来添加新边,使得每次改变就改变logn个节点,很多节点重复利用,达到节省空间的目的. 1.不带修改的区间第K大. HDU-2665 ...
- Splay树求第k大模板
今天上午借着休息日得机会手撸了一下模板,终于对着模板调出来了.prev和next占用了std namespace里面的东西,然后报警我上次给关了所以.....就花了3个小时吧. inline加不加无所 ...
随机推荐
- IIS部署asp.net报404错误
1).所建网站->(右键)权限->"ASP.NET计算机帐户"是否已添加. 2).所建网站->(右键)属性->ASP.NET选项卡->版本是否 ...
- 《转载》常用算法经典代码(C++版)
转自:http://blog.renren.com/blog/311453043/736944237 一.快速排序 void qsort(int x,int y) //待排序的数据存放在a[1]..a ...
- thinkphp模版调用函数方法
原文:thinkphp模版调用函数方法 {变量|函数1|函数2|函数3=参数1,参数2,参数3,###} ###为第4个参数,代表变量替换为第4个参数 举例: {$username|substr=0, ...
- IOT表优缺点
<pre name="code" class="html">IOT表是将所有东西都塞到叶块中,表就是索引,可以避免回表 首先,对于IOT而言,只有索 ...
- 创作gtk源码级vim帮助文档 tags
创作gtk源码级vim帮助文档 tags 缘由 那只有看到源码了.在linux源码上有个网站 http://lxr.linux.no /+trees, 可以很方面的查出相应版本的代码实现,gtk没有. ...
- Windows查看进程taskList,终止进程tskill
TaskList: 列出当前所有运行进程. 使用方法:在命令提示符中输入tasklist 然后回车,会看到类似下面的列表: 映像名称 ...
- Core Data 和 sqlite3的性能对比【图】3gs,iPhone4,4s,5的性能测试。
demo 和源码再此下载 :http://download.csdn.net/detail/hherima/5603797
- [IDEs]Eclipse设置花括号样式
用惯Vistual Studio,在使用Eclipse时发现有很多东西还是挺不习惯,第一个就要解决花括号的样式 步骤: 1.Windows->Preferences->Java->C ...
- iOS 如何创建单例对象
一.什么是单例? 说到单例我就想起了我的java啊 ,不禁感叹起我的大学时光,学了4年的java开发,到现在还是放弃了我的java,踏入了iOS的行列. 算了,入正轨,我现在正是铁树银花的青春美少女, ...
- C++&&Mysql&&codeblocks
#include <iostream> #include <stdio.h> #include <winsock2.h> #include <mysql.h& ...