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. 增大PHP允许上传的文件大小;解决POST Content-Length exceeds the limit

    在php.ini中: upload_max_filesize = 1000M ;1GB post_max_size = 1000M 然后重启apache 参考链接

  2. [转]Using the Repository Pattern with ASP.NET MVC and Entity Framework

    本文转自:http://www.codeguru.com/csharp/.net/net_asp/mvc/using-the-repository-pattern-with-asp.net-mvc-a ...

  3. Android开发学习——Volley框架

    转载至: http://blog.csdn.net/guolin_blog/article/details/17482095 一些概念性的东西 大家进入上边链接理解,我贴一下 具体的实现代码: pub ...

  4. 跨库导表数据(sql)

    程序员用 列子: insert into "000".tbFreeReportselect ReportCode ,ReportName ,GroupNamefrom openda ...

  5. 在JAVA中封装JSONUtils工具类及使用 (转)

    import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util. ...

  6. 无聊的我写了一个代码 。。。P1605 迷宫

    搜索水题 哎 直接不行了 . #include <ctype.h> #include <cstdio> void read(int &x) { x=;char ch=g ...

  7. K近邻法(K-Nearest Neighbor,KNN)

    KNN是一种基本分类与回归方法,本篇只总结分类问题中的KNN. 输入:样本的特征向量,对应于特征空间中的点 输出:样本的类别,可取多类 算法思想:给定一个样本类别已知的训练数据集,对于新样本,根据其K ...

  8. chfn - 改变你的finger讯息

    总览 SYNOPSIS chfn [ -f full-name ] [ -o office ] [ -p office-phone ] [ -h home-phone ] [ -u ] [ -v ] ...

  9. ubuntu 安装virt-manager

    sudo apt-get install qemu-kvm libvirt-bin virt-manager bridge-utils

  10. print keys %map_function 输出 散列的值: OK_funcsplit_funcpackage_VAR

    my %map_function = (     88     "OK_func" => "open_statement",     89     &qu ...