划分树 静态第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加不加无所 ...
随机推荐
- 介绍SAP预留函数创建搜索帮助
紧接上一节介绍的SAP预定义的出口函数F4IF_SHLP_EXIT_EXAMPLE创建搜索帮助, 该函数主要有两个部分: Changing接口的参数属性如下: SHLP:搜索帮助的基础描述,包括搜索帮 ...
- Webbrowser加载Flash后方向键失效问题(用到了OLE接口,没有被处理就转发,够复杂的)
原文:http://blog.csdn.net/dropme/article/details/6253528 窗体上放一个ApplicationEvent控件,OnMessage事件中这么写 uses ...
- Delphi代码中嵌入ASM代码(简单明了)
前言 Delphi作为一个快速高效的开发平台,使用的人越来越多,但熟悉在Delphi代码中嵌入ASM代码的程序员我想不多,因为这方面的资料太少了,另一方面,它还需要有基本的汇编语言知识,关於汇编语言的 ...
- java开发异常类型汇总
1. java.lang.nullpointerexception 这个异常大家肯定都经常遇到,异常的解释是"程序遇上了空指针",简单地说就是调用了未经初始化的对象或者是不存在的对 ...
- [UVALive 6663 Count the Regions] (dfs + 离散化)
链接:https://icpcarchive.ecs.baylor.edu/index.php? option=com_onlinejudge&Itemid=8&page=show_p ...
- Swift - 使用网格(UICollectionView)进行流布局
一.网格UICollectionView最典型的例子是iBooks.其主要属性如下: 1,layout 该属性表示布局方式,有Flow.Custom两种布局方式.默认是Flow流式布局. 2,Acce ...
- ps中图层混合模式、多图层叠加、不透明度、填充、图层样式详解
图像领域中,通过进行一下想法的时候,都要通过用ps看下是不是合理,而ps中图层是必用的一个功能,下面详解一下图层有关的叠加原理. 基本顺序是图层从下往上继续, 先计算图层的填充,再计算样式.最后计算不 ...
- python语言学习5——输入和输出
输出 用print()在括号中加上字符串,就可以向屏幕上输出指定的文字. 注意点: 字符串用的是单引号 碰到逗号输出时就会输出一个空格 输入 python提供了一个input(),可以让用户输入一个字 ...
- (hdu 简单题 128道)平方和与立方和(求一个区间的立方和和平方和)
题目: 平方和与立方和 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- spring MVC拦截器01
spring MVC拦截 作用:身份校验,权限检查,防止非法訪问. 场景:一个bbs系统,用户没有登录就无法发帖或者删除评论; 一个博客系统,没有登录就无法发表博文,无法添加分类,无法删除博文. sp ...