划分树是保存了快速排序的过程的树,可以用来求静态第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. React-TodoList

    React入门最好的学习实例-TodoList 前言 React 的核心思想是:封装组件,各个组件维护自己的状态和 UI,当状态变更,自动重新渲染整个组件. 最近前端界闹的沸沸扬扬的技术当属react ...

  2. hdu1569find the safest road(floyd变形求最大安全值)

    find the safest road Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  3. FatMouse&#39; Trade(杭电1009)

    FatMouse' Trade Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Tot ...

  4. ThinkPhp学习10

    原文:ThinkPhp学习10 查询操作 Action模块 User下的search public function search(){ //判断username是否已经传入,且不为空 if(isse ...

  5. haproxy 服务端超时时间 timeout server 17000 --后台程序17秒没有响应,返回超时

    haproxy 服务端超时时间: haproxy 配置: timeout server 17000 --后台程序17秒没有响应,返回超时 Jun 27 09:29:56 localhost hapro ...

  6. 利用WinDbg找出程序崩溃的代码行号

    之前碰到论坛里有几个好友,说程序不时的崩溃,什么xxoo不能read的! 如果光要是这个内存地址,估计你会疯掉~~ 所以分享一下基本的调试技巧,需要准备的工具有WinDbg + VC6.0, 下面是自 ...

  7. [Django实战] 第4篇 - 用户认证(用户登录)

    今天来实现用户登录模块 首先,我们创建一个表单(forms.py): from django import forms from django.contrib.auth.models import U ...

  8. poj 3450 Corporate Identity

    题目链接:http://poj.org/problem?id=3450 题目分类:后缀数组 题意:求n个串的最长公共字串(输出字串) //#include<bits/stdc++.h> # ...

  9. thinkPHP四种URL访问方式(二)

    原文:thinkPHP四种URL访问方式(二) 四.url的4种访问方式      1.PATHINFO 模式 -- (重点) http://域名/项目名/入口文件/模块名/方法名/键1/值1/键2/ ...

  10. java之jvm学习笔记五(实践写自己的类装载器)

    java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...