划分树 poj2104 hdu5249

KPI

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 616    Accepted Submission(s): 261

Problem Description

你工作以后, KPI 就是你的所有了. 我开发了一个服务。取得了非常大的知名度。数十亿的请求被推到一个大管道后同一时候服务从管头拉取请求。让我们来定义每一个请求都有一个重要值。我的KPI是由当前管道内请求的重要值的中间值来计算。如今给你服务记录,有时我想知道当前管道内请求的重要值得中间值。

Input

有大约100组数据。

每组数据第一行有一个n(1≤n≤10000),代表服务记录数。

接下来有n行。每一行有3种形式

"in x": 代表重要值为x(0≤x≤109)的请求被推进管道。

"out": 代表服务拉取了管道头部的请求。

"query: 代表我想知道当前管道内请求重要值的中间值. 那就是说,假设当前管道内有m条请求, 我想知道。升序排序后第floor(m/2)+1th
条请求的重要值.

为了让题目简单,全部的x都不同。而且假设管道内没有值。就不会有"out"和"query"操作。

Output

对于每组数据。先输出一行

Case #i:

然后每一次"query"。输出当前管道内重要值的中间值。

Sample Input

6
in 874
query
out
in 24622
in 12194
query

Sample Output

Case #1:
874
24622

K-th Number

Time Limit: 20000MS   Memory Limit: 65536K
Total Submissions: 41138   Accepted: 13447
Case Time Limit: 2000MS

Description

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 109 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大数,假设用快排之后,再查,复杂度太大。不能过,就要用到划分树了,划分树。事实上,就是线段树的

一个变种了,当然,这样做查询是lg(n)级别,建树是n * lg(n),再加上一次快排,也是n * lg(n),差点儿相同就能够过了!

先来看看划分树,我们在线段树的基础上,假设每一个结点都保存了。当前子段向左子树走的个数。假设,查询的k要小于,查询段向左走的个数,自然,我们向左子树就能够查到结果。假设,k>向左走的个数,当然要向右找k-midcount个数,区间的变换。我们能够

推一下向左走就是l + scount, l + ecount - 1。向右走就是mid + 1 + s - l - scount, mid + 1 + e - l - ecount,当中scount就是s之前向左走的个数。 ecount,就是e之前向左走的个数。

上核心代码

#define MID(a,b) (((a)+(b))>>1)
#define N 100050
int num[20][N], val[20][N];
//第i层,向左包含自已,向左子树的个数,当前的值
int pri[N], sorted[N];
//原始和排序后的数列
char str[20];
void build(int l, int r, int layer){
	if (l >= r){
		return;
	}
	int mid = MID(l, r);
	int ql = l, qr = mid + 1, leftCount = mid, eqCount = 0;
	for (int i = l; i <= r; i++)
		leftCount -= val[layer][i] < sorted[mid];
	for (int i = l; i <= r; i++){
		if (i == l){
			num[layer][i] = 0;
		}
		else{
			num[layer][i] = num[layer][i - 1];
		}
		if (val[layer][i] < sorted[mid]){
			num[layer][i]++;
			val[layer + 1][ql++] = val[layer][i];
		}
		else if (val[layer][i] > sorted[mid]){
			val[layer + 1][qr++] = val[layer][i];
		}
		else {
			if (eqCount < leftCount){
				eqCount++;
				num[layer][i]++;
				val[layer + 1][ql++] = val[layer][i];
			}
			else {
				val[layer + 1][qr++] = val[layer][i];
			}
		}
	}
	build(l, mid, layer + 1);
	build(mid + 1, r, layer + 1);
}
//在layer层l到r间,找s-e之间的第k大数
int query(int l, int r, int layer, int s, int e, int k){
	if (l >= r || s >= e){
		return val[layer][s];
	}
	int scount, ecount, mid = MID(l, r);
	if (s == l){
		scount = 0, ecount = num[layer][e];
	}
	else {
		scount = num[layer][s - 1], ecount = num[layer][e];
	}
	int midcount = ecount - scount;
	if (k <= midcount){
		return query(l, mid, layer + 1, l + scount, l + ecount - 1, k);
	}
	else {
		return query(mid + 1, r, layer + 1, mid + 1 + s - l - scount, mid + 1 + e - l - ecount, k - midcount);
	}
}
int main()
{
	int tcase, tcasenum = 0;
	int n, k, q, s, e, begin = 1, nn, qcount, m;
	while (S2(n, m) != EOF)
	{
		FI(n){
			S(val[0][i+1]);
		}
		FI(n){
			sorted[i + 1] = val[0][i + 1];
		}
		sort(sorted + 1, sorted + n + 1);
		build(1, n, 0);
		FI(m){
			S2(s, e); S(q);
			Prn(query(1, n, 0, s,e,q));
		}
	}
	return 0;
}
时间: 2024-12-21 21:50:54

划分树 poj2104 hdu5249的相关文章

poj2104 划分树 区间K大 在线 无修改

博主sbit....对于高级数据结构深感无力,然后这些东西在OI竟然烂大街了,不搞就整个人都不好了呢. 于是我勇猛的跳进了这个大坑 ——sbit 区间K大的裸题,在线,无修改. 可以用归并树(\(O(nlog^3n)\)),也可用划分树(\(O(nlogn + mlogn)\)).果断划分树...(以后再来看归并树...再来看...来看..看..) 划分树是个什么东西呢?为什么可以做区间k大呢? 想想平衡树做k大时是如何搞的,其实内在原理是一样的. 划分树分两个步骤:建树与询问,这两个步骤相互关

划分树(poj2104)

poj2104 题意:给出n个数,有m次查询,每次查询要你找出 l 到 r 中第 k 大的数: 思路:划分树模板题 上述图片展现了查询时如何往下递推的过程 其中ly表示 [sl,l) 中有多少个数进入了左子树,num[ceng][r]表示[sl,r]中有多少个数进入了左子树,total表示[l,r]中有多少个数进入了左子树. 代码: #include<cstdio> #include<algorithm> using namespace std; int s[20][100010]

划分树 静态第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;

杭电ACM2665——Kth number~~划分树

题目的意思:给点区间[a, b],查找第K大的数,和POJ2104题一样,只是HDU上的时间限制5000MS,用我在POJ上的方法,过不了,会超时. 而这一题的代码,改一下main函数的输入,就可以直接AC了POJ上的2104. 这题,用分桶法,WR,纠结了一晚上,最后还是放弃了,实在不知道错在哪里.于是改用了划分树的方法,学习了划分树的建立和查找. 划分树:主要运用于求解序列中区间[a, b]上的第K大的数,也就是区间[a, b]从小到大排序,第K个. 主要的算法思路是: 1,建树:先排序好存

划分树基础知识

原网址:划分树详解 对4 5 2 8 7 6 1 3 分别建划分树和归并树 划分树如下图 红色的点是此节点中被划分到左子树的点. 我们一般用一个结构体数组来保存每个节点,和线段树不同的是,线段树每个节点值保存一段的起始位置和结束位置,而在划分树和递归树中,每个节点的每个元素都是要保存的.为了直观些,我们可以定义一个结构体数组,一个结构体中保存的是一层的元素和到某个节点进入左子树的元素的个数,不同于线段树,我们不能保存一个节点的起始结尾位置,因为随层数的增加,虽然每个结构体保存的元素数目是一定的,

hdu-4417 Super Mario(树状数组 + 划分树)

题目链接: Super Mario Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others) Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is

HDU 3473 Minimum Sum 划分树,数据结构 难度:1

http://acm.hdu.edu.cn/showproblem.php?pid=3473 划分树模板题目,需要注意的是划分树的k是由1开始的 划分树: 参考:http://blog.csdn.net/shiqi_614/article/details/8041390 划分树的定义 划分树定义为,它的每一个节点保存区间[lft,rht]所有元素,元素顺序与原数组(输入)相同,但是,两个子树的元素为该节点所有元素排序后(rht-lft+1)/2个进入左子树,其余的到右子树,同时维护一个num域,

hdu 2665 Kth number(划分树)

Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4602 Accepted Submission(s): 1468 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first l

HDU 4417 划分树+二分

题意:有n个数,m个询问(l,r,k),问在区间[l,r] 有多少个数小于等于k. 划分树--查找区间第k大的数.... 利用划分树的性质,二分查找在区间[l,r]小于等于k的个数. 如果在区间第 i 大的数tmp>k,则往下找,如果tmp<k,往上找. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #incl