划分树是保存了快速排序的过程的树,可以用来求静态第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. DFA最小化 -- Hopcroft算法 Python实现

    wiki 伪代码看上去一直以为怪.发现葡萄牙语和俄罗斯语那里的 if 推断都还缺少一个条件. 国内的资料比較少.这几份学习资料不错.比我稀里糊涂的思路要好,分享下: http://www.liafa. ...

  2. Android L动画入门

    Android L带来了许多新特性,其中就包括了大量的动画效果,你可以在自己的应用中使用.本文中我将详解这些动画和如何在应用中使用.本文中的所有代码可以在github上找到. 波纹和强调 现在安卓支持 ...

  3. Git 图解剖析(转)

    git中文件内容并没有真正存储在索引(.git/index)或者提交对象中,而是以blob的形式分别存储在数据库中(.git/objects),并用SHA-1值来校验. 索引文件用识别码列出相关的bl ...

  4. PowerShell与Unix Shell对比:八大实例

    PowerShell与Unix Shell对比:八大实例 本文将从八个实例对比PowerShell和Unix Shell,通常是Linux Bourne Shell(包括sh.ksh和bash等).二 ...

  5. dumpbin

    在使用VC时,可以用DUMPBIN.EXE来得到某个DLL中所输出的符号的清单.如下面的 命令:dumpbin -exports Cmpnt1.dll如: C:/WINDOWS/system32> ...

  6. 网络知识汇总(2) - Linux下如何修改ip地址

    在Linux的系统下如何才能修改IP信息   以前总是用ifconfig修改,重启后总是得重做.如果修改配置文件,就不用那么麻烦了-   A.修改ip地址   即时生效:   # ifconfig e ...

  7. PageHeap,调试Heap问题的工具

    <Windows用户态程序高效排错>第二章主要介绍用户态调试相关的知识和工具.本文主要讲了PageHeap,调试Heap问题的工具. AD:51CTO学院:IT精品课程在线看! 2.4.2 ...

  8. Core Data 和 sqlite3的性能对比【图】3gs,iPhone4,4s,5的性能测试。

    demo 和源码再此下载  :http://download.csdn.net/detail/hherima/5603797

  9. 奔小康赚大钱 hdu 2255

    奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  10. abap alv multiple header using write

    A standard SAP ALV list report will show only one line header, but there will be a requirement somed ...