K-th Number POJ - 2104 划分树
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 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
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
题解:
划分树,类似线段树,主要用于求解某个区间的第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 划分树的更多相关文章
- K-th Number Poj - 2104 主席树
K-th Number Poj - 2104 主席树 题意 给你n数字,然后有m次询问,询问一段区间内的第k小的数. 解题思路 这个题是限时训练做的题,我不会,看到这个题我开始是拒绝的,虽然题意清晰简 ...
- poj 2104 划分树
思路:裸的划分树 #include<iostream> #include<algorithm> #include<cstring> #include<cstd ...
- hdu 4417,poj 2104 划分树(模版)归并树(模版)
这次是彻底把划分树搞明确了,与此同一时候发现了模版的重要性.敲代码一个字符都不能错啊~~~ 划分树具体解释:点击打开链接 题意:求一组数列中随意区间不大于h的个数. 这个题的做法是用二分查询 求给定 ...
- 主席树 【权值线段树】 && 例题K-th Number POJ - 2104
一.主席树与权值线段树区别 主席树是由许多权值线段树构成,单独的权值线段树只能解决寻找整个区间第k大/小值问题(什么叫整个区间,比如你对区间[1,8]建立一颗对应权值线段树,那么你不能询问区间[2,5 ...
- K-th Number POJ - 2104
K-th Number POJ - 2104 You are working for Macrohard company in data structures department. After fa ...
- 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 ...
- hdu 2665 Kth number (poj 2104 K-th Number) 划分树
划分树的基本功能是,对一个给定的数组,求区间[l,r]内的第k大(小)数. 划分树的基本思想是分治,每次查询复杂度为O(log(n)),n是数组规模. 具体原理见http://baike.baidu. ...
- [poj 2104]主席树+静态区间第k大
题目链接:http://poj.org/problem?id=2104 主席树入门题目,主席树其实就是可持久化权值线段树,rt[i]维护了前i个数中第i大(小)的数出现次数的信息,通过查询两棵树的差即 ...
- poj 2104 主席树(区间第k大)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 44940 Accepted: 14946 Ca ...
随机推荐
- 【先定一个小目标】Ubuntu 16.04 搭建 zookeeper
ZooKeeper 是 Apache 的一个顶级项目,为分布式应用提供高效.高可用的分布式协调服务,提供了诸如数据发布/订阅.负载均衡.命名服务.分布式协调/通知和分布式锁等分布式基础服务.由于 Zo ...
- ORACLE数据库的备份分为物理备份和逻辑备份两种。
物理备份是将实际组成数据库的操作系统文件从一处拷贝到另一处的备份过程,通常是从磁盘到磁带.可以使用 Oracle 的恢复管理器(Recovery Manager,RMAN)或操作系统命令进行数据库的物 ...
- 转】在Ubuntu中安装Cassandra
原博文出自于: http://blog.fens.me/category/%E6%95%B0%E6%8D%AE%E5%BA%93/ 感谢! Posted: Mar 22, 2014 Tags: cas ...
- Xml学习笔记(1)
不同的xml文档构可能要用到不同的方法进行解析这里用到的是例如<student name="张三" id="1" sex="男"/&g ...
- 调用wsdl接口,参数是xml格式
1.最近太累了,好困.闲话少许直奔主题吧.上代码 try{ String wsurl = "http://172.16.16.236:9999/xxx/ws/WSService?wsdl&q ...
- 8.JAVA-向上转型、向下转型
父子对象之间的转换分为了向上转型和向下转型,它们区别如下: 向上转型 : 通过子类对象(小范围)实例化父类对象(大范围),这种属于自动转换 向下转型 : 通过父类对象(大范围)实例化子类对象(小范围) ...
- hihocoder offer收割编程练习赛12 C 矩形分割
思路: 模拟,深搜. 实现: #include <iostream> #include <cstdio> #include <string> using names ...
- Android与H5互调(通过实例来了解Hybrid App)
前些日子,Android原生开发将被取缔的吵得火热,JavaScript是能做一个完全的APP,但只使用JavaScript做出来的APP也不会牛逼到哪里去.最好的是混合(Hybrid)开发,在需要的 ...
- linux下php开启pdo扩展
前提:网页报错 为解决问题:Undefined class constant 'MYSQL_ATTR_INIT_COMMAND' 解决方案 : 下载安装PHP_MYSQL扩展 wget http:// ...
- iOS---UICollectionView详解和常用API翻译
UICollectionView 1.必须要设置布局参数 2.注册cell 用法类似于UITableView 类.自动实现重用,必须注册初始化. 使用UICollectionView必须实现UICol ...