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 ...
随机推荐
- Hibernate3的hbm文件错误引用dtd文件导致项目无法启动问题处理
错误信息: org.hibernate.InvalidMappingException: Could not parse mapping document from resource /***/*** ...
- 来自AJPFX的二分法查找
package com.heima.array; public class Demo2_Array { /** * * A:案例演示 * ...
- LN : leetcode 70 Climbing Stairs
lc 70 Climbing Stairs 70 Climbing Stairs You are climbing a stair case. It takes n steps to reach to ...
- Java线程-线程的基本状态
问题:线程有哪些基本状态?这些状态是如何定义的? 新建(new):新创建了一个线程对象. 可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法.该状 ...
- 搜索可用docker镜像
简介:这一步的目标是学会使用docker search命令来检索可用镜像. 搜索可用的docker镜像 目标: 提示: 正确的命令: 搜索可用的docker镜像 使用docker最简单的方式莫过于从现 ...
- ASP.NET Excel下载方法一览
方法一 通过GridView(简评:方法比较简单,但是只适合生成格式简单的Excel,且无法保留VBA代码),页面无刷新 aspx.cs部分 using System; using System.Co ...
- Farseer.net轻量级ORM开源框架 V1.x 入门篇:视图的数据操作
导航 目 录:Farseer.net轻量级ORM开源框架 目录 上一篇:Farseer.net轻量级ORM开源框架 V1.x 入门篇:视图实体类映射 下一篇:Farseer.net轻量级ORM开源 ...
- viewport 640宽的做法 针对iphone和安卓单独设置
<!DOCTYPE html> <html lang="ch"> <head> <meta charset="utf-8&quo ...
- 0.ssm web项目中的遇到的坑
1.自定义的菜单,href为项目的相对路径,即: : 点击一个菜单,后再点击另一个菜单,然后发现浏览器地址栏的链接是在上一个链接后面拼接的,也就报错了. 解决办法: 每一个菜单的href前增加&quo ...
- node.js 的介绍
1.node.js是什么? (1)node.js不是一门编程语言, 是一个开发平台,就像Java开发平台,Net平台,PHP开发平台,Apple开发平台.(何为开发平台?有对应的编程语言,有语言运行时 ...