1. 程式人生 > >POJ 2104 K-th Number(主席樹,區間第K大的數)

POJ 2104 K-th Number(主席樹,區間第K大的數)

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

求區間中第k大的數。

#include <iostream>
#include <algorithm>
#define MAXN 100010
using namespace std;
int T, n, m, tot, a[MAXN], b[MAXN], cnt;
//T為測試樣例數,n為元陣列個數,m為查詢個數,tot為建樹的新節點
//a為原數列,b用來離散化的數列,其unique後元素的個數為cnt
struct N {
	int ls, rs, w;
	//ls左結點下標,rs右結點下標,w區間元素個數
}tree[30*MAXN];
int root[MAXN];//記錄每棵樹的根節點下標
int Build_tree(int l, int r) {//建樹
	int newnode = tot++;
	tree[newnode].w = 0;
	if(l != r) {
		int mid = (l + r) >> 1;
		tree[newnode].ls = Build_tree(l, mid);
		tree[newnode].rs = Build_tree(mid + 1, r);		
	}
	return newnode;
}
int update(int rt, int pos, int  val) {
	int newnode = tot++;
	int temp = newnode;
	tree[newnode].w = tree[rt].w + val;
	int l = 1, r = cnt;
	while(l < r) {
		int mid = (l + r) >> 1;
		if(pos <= mid) {
			tree[newnode].ls = tot++;
			tree[newnode].rs = tree[rt].rs;
			newnode = tree[newnode].ls;
			rt = tree[rt].ls;
			r = mid;
		} else {
			tree[newnode].ls = tree[rt].ls;
			tree[newnode].rs = tot++;
			newnode = tree[newnode].rs;
			rt = tree[rt].rs;
			l = mid + 1;
		}
		tree[newnode].w = tree[rt].w + val;
	}
	return temp;
}
int query(int rt1, int rt2, int k) {
	int l = 1, r = cnt;
	while(l < r) {
		int mid = (l + r) >> 1;
		int tmp = tree[tree[rt2].ls].w - tree[tree[rt1].ls].w;
		if(tmp >= k) {
			rt1 = tree[rt1].ls;
			rt2 = tree[rt2].ls;
			r= mid;
		} else {
			k -= tmp;
			rt1 = tree[rt1].rs;
			rt2 = tree[rt2].rs;
			l = mid + 1;
		}
	}
	return l;
}
int main() {
		scanf("%d %d", &n, &m);
		for(int i = 1; i <= n; i++) {
 			scanf("%d", &a[i]);
 			b[i - 1] = a[i];
		}
		sort(b, b + n);
		cnt = unique(b, b + n) - b;
		tot = 0;
		root[0] = Build_tree(1, cnt);
		for(int i = 1; i <= n; i++) {
			int tmp = (int)(lower_bound(b, b + cnt, a[i]) - b) + 1;
			root[i] = update(root[i - 1], tmp, 1);
		}
		int l, r, k;
		for(int i = 0; i < m; i++) {
			scanf("%d %d %d", &l, &r, &k);
			int tmp = query(root[l - 1], root[r], k);
			printf("%d\n", b[tmp - 1]);
		}
	return 0;
}

相關推薦

POJ 2104 K-th Number主席區間K大的數

Description You are working for Macrohard company in data structures department. After failing your previous task about key insertion you

HDU 2665 Kth number主席靜態區間K題解

可持久化 unique algorithm using 主席樹 可持久化線段樹 long spa 靜態區 題意:問你區間第k大是誰 思路:主席樹就是可持久化線段樹,他是由多個歷史版本的權值線段樹(不是普通線段樹)組成的。 具體可以看q學姐的B站視頻 代碼:

POJ 2104 K-th Number主席

ber sca first n) 次數 example == scan sorted K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 5742

poj 2104 K-th Number 主席入門模板題

摘抄了一段主席樹的解釋:所謂主席樹呢,就是對原來的數列[1..n]的每一個字首[1..i](1≤i≤n)建立一棵線段樹,線段樹的每一個節點存某個字首[1..i]中屬於區間[L..R]的數一共有多少個(比如根節點是[1..n],一共i個數,sum[root]

poj 2104 K-th Number 主席模板

傳送門 // by spli #include<cstring> #include<cstdio> #include<algorithm> #include<iostream> using namespace

POJ 2104 K-th Number 劃分主席寫過了這次是整體二分解法

還是先描述一下題意: 給出一個長度為n的數列,m次詢問區間內的第k大數 對劃分樹,主席樹和整體二分通過這題做了一下比較 劃分樹  1000ms+ 主席樹 2000ms+ 整體二分 1500ms+ 整體二分介於兩者之前,對於這題複雜度約莫是O( (n+m)log(n+m)l

poj2104 K-th Number 主席入門題|模板題

K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 48751 Accepted: 16447 Case Time Limit: 2000MS Description Y

POJ2104————K-th Number線段二分法

K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 51227 Accepted: 17511 Case Time Limit: 2000MS Description

POJ2104主席區間K

模板題,模板來自B站UESTCACM #include <iostream> #include <algorithm> #include <queue> #in

zoj 3886 Nico Number線段區間取模操作

題目連結 Nico Number Time Limit: 2 Seconds      Memory Limit: 262144 KB Kousaka Honoka and Minami Kotori are playing a game about a secret

POJ 2104 K-th Number 劃分 / 主席

Description You are working for Macrohard company in data structures department. After failing yo

POJ 2104 K-th Number 主席(求區間k大)

主席書資料 題意:給出n個數,m次詢問,[x,y]內第k小的數時多少?n<=1e5,m<=5000 主席樹:對原序列的每個字首i都建立一個線段樹 維護值域[l,r]中的每個數,在字首i的

[poj 2104]主席+靜態區間k

include end 區間 得到 name int 題目 tar tdi 題目鏈接:http://poj.org/problem?id=2104 主席樹入門題目,主席樹其實就是可持久化權值線段樹,rt[i]維護了前i個數中第i大(小)的數出現次數的信息,通過查詢兩棵樹的差

poj 2104主席區間k

區間 ++ cto ast http lan air algorithm while POJ - 2104 題意:求區間第k小 思路:無修改主席樹 AC代碼: #include "iostream" #include "iomanip" #include "string.

解決K-th Number主席

K-th Number 1.主席樹解法 前方高能,你需要(一些線段樹姿勢) 答記者問 Q:為什麼叫主席樹?叫主席樹會不會給人一種欽定的感覺? A:因為某大佬考場上忘記怎麼寫劃分樹了,於是當場yy出來了,叫主席樹跟樹本身特徵沒關係(至少我這麼

POJ_2104 K-th Number主席

uil 持久化 就是 lan pan lower 構造 宋體 之前 一 題面   K-th Number 二 分析   第一個主席樹的題,感觸蠻多吧,幾個關鍵點就是可持久化數據結構,這裏的主席樹其實就是保留了之前各個版本的權值線段樹,然後利用權值線段樹和歷史版本可以進

A - K-th Number POJ - 2104 -主席第一彈-K大的數

感謝:http://www.cnblogs.com/zyf0163/p/4749042.html https://blog.csdn.net/qq_24451605/article/details/49031123 裸題多次查詢給定區間L—R內第K大的數 #include&

poj 2104K-th Number整體二分+狀陣列

傳送門biu~ 題目大意:給一串數字,多次詢問區間的第k小值。 思路:首先考慮一次詢問的情況,我們可以二分答案,然後通過驗證比答案大的數有多少個來不斷地縮小答案範圍直至得到一個準確的答案。而對於多個

poj 2104 <排序分塊區間k大>/<第一次用主席>2個方法+整體二分

給一個序列,查詢區間第k大,用分塊來實現 首先將區間分為每塊block大小,也就有num=n/block塊,if(n%block==0)num++. 然後每次在定義每個塊其左右邊界的時候進行排序,那麼就得到一個每塊內排好序的塊。 查詢的時候因為是查詢區間第k大,那麼我們

poj2104 K-th Number整體二分+狀陣列

DescriptionYou are working for Macrohard company in data structures department. After failing your previous task about key insertio