K-th Number
You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment. 
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?" 
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.

Input

The first line of the input file contains n --- the size of the array, and m --- the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000). 
The second line contains n different integer numbers not exceeding 10 9 by their absolute values --- the array for which the answers should be given. 
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).

Output

For each question output the answer to it --- the k-th number in sorted a[i...j] segment.

Sample Input

7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3

Sample Output

5
6
3

Hint

This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.
 
 
题解:
以前用主席树写过,现在学习了一下划分树。

划分树,类似线段树,主要用于求解某个区间的第k 大元素(时间复杂度log(n)),快排本也可以快速找出,但快排会改变原序列,所以每求一次都得恢复序列。

  下面就以 POJ 2104 进行解说:

  题目意思就是,给你n 个数的原序列,有m 次询问,每次询问给出l、r、k,求原序列l 到r 之间第k 大的数。n范围10万,m范围5千,这道题用快排也可以过,快排过的时间复杂度n*m,而划分树是m*logn(实际上应该是nlogn才对,因为建图时间是nlogn,n又比m大),分别AC后,时间相差很明显。

  划分树,顾名思义是将n 个数的序列不断划分,根结点就是原序列,左孩子保存父结点所有元素排序后的一半,右孩子也存一半,也就是说排名1 -> mid的存在左边,排名(mid+1) -> r 的存在右边,同一结点上每个元素保持原序列中相对的顺序。见下图:

   

  红点标记的就是进入左孩子的元素。

  当然,一般不会说每个结点开个数组存数,经观察,每一层都包含原本的n 个数,只是顺序不同而已,所以我们可以开val[20][N]来保存,也就是说共20层,每一层N个数。

  我们还需要一个辅助数组num,num[i]表示i 前面有多少数进入左孩子(i 和i 前面可以弄成本结点内也可以是所有,两种风格不同而已,下面采取的是本结点内),和val一样,num也开成num[20][N],来表示每一层,i 和i 前面(本结点)有多少进入左孩子。

  第一层:1 进入左孩子,num[1]=1,5 进入右孩子,num[2]=1,...,num[8]=4。

  第二层:5 进入左孩子,num[5]=1,6 进入右孩子,num[6]=1,...,num[8]=2。

  建图时就是维护每一层val[]和num[]的值就可以了。

很是清晰的,

最后那个询问其实不难,自己一开始瞎比比了一会,卡了许久时间。

    这样子转换一下,多仔细考虑转换l,r那一段。

 #include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstdio> #define N 100007
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if (ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n,m;
int a[N],val[][N],num[][N]; void build(int deep,int l,int r)
{
if (l==r) return;
int mid=(l+r)>>,same=mid-l+;
for (int i=l;i<=r;i++)
if (val[deep][i]<a[mid]) same--;
int lh=l,rh=mid+;
for (int i=l;i<=r;i++)
{
if (i==l) num[deep][i]=;
else num[deep][i]=num[deep][i-];
if (val[deep][i]<a[mid] || val[deep][i]==a[mid]&&same>)//没有same那么所以有和a[mid]一样大的树都会进入做子树
{
val[deep+][lh++]=val[deep][i];
num[deep][i]++;
if (val[deep][i]==a[mid]) same--;
}
else val[deep+][rh++]=val[deep][i];
}
build(deep+,l,mid),build(deep+,mid+,r);
}
int query(int deep,int l,int r,int x,int y,int k)
{
if (l==r) return val[deep][l];
int ly,mid=(l+r)>>;
if (x==l) ly=;
else ly=num[deep][x-];
int sum=num[deep][y]-ly;//表示放在左边有多少。
if (sum>=k) return query(deep+,l,mid,l+ly,l+num[deep][y]-,k);//转换到这一段区间放入做子树的那一段。
else
{
int lr=mid++(x-l-ly);
return query(deep+,mid+,r,lr,lr+y-x+-sum-,k-sum);
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for (int i=;i<=n;i++)
a[i]=read(),val[][i]=a[i];
sort(a+,a+n+);
build(,,n);
for (int i=;i<=m;i++)
{
int l=read(),r=read(),k=read();
printf("%d\n",query(,,n,l,r,k));
}
}
}

K-th Number POJ - 2104 划分树的更多相关文章

  1. K-th Number Poj - 2104 主席树

    K-th Number Poj - 2104 主席树 题意 给你n数字,然后有m次询问,询问一段区间内的第k小的数. 解题思路 这个题是限时训练做的题,我不会,看到这个题我开始是拒绝的,虽然题意清晰简 ...

  2. poj 2104 划分树

    思路:裸的划分树 #include<iostream> #include<algorithm> #include<cstring> #include<cstd ...

  3. hdu 4417,poj 2104 划分树(模版)归并树(模版)

    这次是彻底把划分树搞明确了,与此同一时候发现了模版的重要性.敲代码一个字符都不能错啊~~~ 划分树具体解释:点击打开链接 题意:求一组数列中随意区间不大于h的个数. 这个题的做法是用二分查询  求给定 ...

  4. 主席树 【权值线段树】 && 例题K-th Number POJ - 2104

    一.主席树与权值线段树区别 主席树是由许多权值线段树构成,单独的权值线段树只能解决寻找整个区间第k大/小值问题(什么叫整个区间,比如你对区间[1,8]建立一颗对应权值线段树,那么你不能询问区间[2,5 ...

  5. K-th Number POJ - 2104

    K-th Number POJ - 2104 You are working for Macrohard company in data structures department. After fa ...

  6. HDU 2665.Kth number-可持久化线段树(无修改区间第K小)模板 (POJ 2104.K-th Number 、洛谷 P3834 【模板】可持久化线段树 1(主席树)只是输入格式不一样,其他几乎都一样的)

    Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  7. hdu 2665 Kth number (poj 2104 K-th Number) 划分树

    划分树的基本功能是,对一个给定的数组,求区间[l,r]内的第k大(小)数. 划分树的基本思想是分治,每次查询复杂度为O(log(n)),n是数组规模. 具体原理见http://baike.baidu. ...

  8. [poj 2104]主席树+静态区间第k大

    题目链接:http://poj.org/problem?id=2104 主席树入门题目,主席树其实就是可持久化权值线段树,rt[i]维护了前i个数中第i大(小)的数出现次数的信息,通过查询两棵树的差即 ...

  9. poj 2104 主席树(区间第k大)

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 44940   Accepted: 14946 Ca ...

随机推荐

  1. Hibernate3的hbm文件错误引用dtd文件导致项目无法启动问题处理

    错误信息: org.hibernate.InvalidMappingException: Could not parse mapping document from resource /***/*** ...

  2. java使用正则表达式对注册页面进行验证

    package regex; import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Patt ...

  3. iOS 集成银联支付(绕过文档的坑,快速集成)-转

    本文是投稿文章,作者:南栀倾寒当初集成支付宝的时候,觉得见了这么丑的代码,加上这么难找的下载地址,在配上几乎为零的文档,寒哥就要吐血了. 下午去集成银联,才知道血吐的早了. 下载地址:https:// ...

  4. android开发学习--网络请求框架RxJava+Retrofit

    看了好多的博客,终于弄清楚了Rxjava和Retrofit,给大家推荐几个不错的文章: https://gank.io/post/56e80c2c677659311bed9841 这个文章是只用Ret ...

  5. Oracle本地动态 SQL

    本地动态 SQL 首先我们应该了解什么是动态 SQL,在 Oracle数据库开发 PL/SQL块中我们使用的 SQL 分为:静态 SQL语句和动态 SQL语句.所谓静态 SQL指在 PL/SQL块中使 ...

  6. ASP.NET Core MVC使用MessagePack配合前端fetch交换数据

    1.安装Nuget包 - WebApiContrib.Core.Formatter.MessagePack https://www.nuget.org/packages/WebApiContrib.C ...

  7. jq星星评分

    html代码 <div class="make_mark"> <h5>请为这次服务打分</h5> <div class="mar ...

  8. ReactJS-3-组件生命周期

    简介 普通的UI应用生命周期一般包括Birth, Growth, Death, React中Component的生命周期也是如此,这是一个持续的过程,贯穿整个应用的生命历程. 阶段 1.mountin ...

  9. SQL——时间戳

    mysql 低版本,date.datetime.timestamp 无法精确到毫秒 可以舍弃时间类型字段,用 bigint 来代替,如果用字符串类型代替,还是比较担心排序的时候只是根据第一个字母进行排 ...

  10. Java递归扫描文件路径

    import java.io.File; public class Test { public static int count = 0; public static void main(String ...