1. 程式人生 > >劃分樹演算法 模板

劃分樹演算法 模板

劃分樹是一種基於線段樹的資料結構。主要用於快速求出(在log(n)的時間複雜度內)序列區間的第k大值 。

劃分樹和歸併樹都是用線段樹作為輔助的,原理是基於快排 和歸併排序 的。
劃分樹的建樹過程基本就是模擬快排過程,取一個已經排過序的區間中值,然後把小於中值的點放左邊,大於的放右邊。並且記錄d層第i個數之前(包括i)小於中值的放在左邊的數。具體看下面程式碼註釋。

這裡寫圖片描述

這裡寫圖片描述

模板

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using
namespace std; #define MAX_SIZE 100005 int sorted[MAX_SIZE];//已經排好序的資料 int toleft[25][MAX_SIZE]; int tree[25][MAX_SIZE]; void build_tree(int left, int right, int deep) { int i; if (left == right) return ; int mid = (left + right) >> 1; int same = mid - left + 1; //位於左子樹的資料
for (i = left; i <= right; ++i) {//計算放於左子樹中與中位數相等的數字個數 if (tree[deep][i] < sorted[mid]) { --same; } } int ls = left; int rs = mid + 1; for (i = left; i <= right; ++i) { int flag = 0; if ((tree[deep][i] < sorted[mid]) || (tree[deep][i] == sorted[mid] && same > 0
)) { flag = 1; tree[deep + 1][ls++] = tree[deep][i]; if (tree[deep][i] == sorted[mid]) same--; } else { tree[deep + 1][rs++] = tree[deep][i]; } toleft[deep][i] = toleft[deep][i - 1]+flag; } build_tree(left, mid, deep + 1); build_tree(mid + 1, right, deep + 1); } int query(int left, int right, int k, int L, int R, int deep) { if (left == right) return tree[deep][left]; int mid = (L + R) >> 1; int x = toleft[deep][left - 1] - toleft[deep][L - 1];//位於left左邊的放於左子樹中的數字個數 int y = toleft[deep][right] - toleft[deep][L - 1];//到right為止位於左子樹的個數 int ry = right - L - y;//到right右邊為止位於右子樹的數字個數 int cnt = y - x;//[left,right]區間內放到左子樹中的個數 int rx = left - L - x;//left左邊放在右子樹中的數字個數 if (cnt >= k) { //printf("sss %d %d %d\n", xx++, x, y); return query(L + x, L + y - 1, k, L, mid, deep + 1); // 因為x不在區間內 所以沒關係 所以先除去,從L+x開始,然後確定範圍 } else { //printf("qqq %d %d %d\n", xx++, x, y); return query(mid + rx + 1, mid + 1 + ry, k - cnt, mid + 1, R, deep + 1); //同理 把不在區間內的 分到右子樹的元素數目排除,確定範圍 } } int main() { int m, n; int a, b, k; int i; while (scanf("%d%d", &m, &n) == 2) { for (i = 1; i <= m; ++i) { scanf("%d", &sorted[i]); tree[0][i] = sorted[i]; } sort(sorted + 1, sorted + 1 + m); build_tree(1, m, 0); for (i = 0; i < n; ++i) { scanf("%d%d%d", &a, &b, &k); printf("%d\n", query(a, b, k, 1, m, 0)); } } return 0; }

相關推薦

劃分演算法 模板

劃分樹是一種基於線段樹的資料結構。主要用於快速求出(在log(n)的時間複雜度內)序列區間的第k大值 。 劃分樹和歸併樹都是用線段樹作為輔助的,原理是基於快排 和歸併排序 的。 劃分樹的建樹過程基本就是模擬快排過程,取一個已經排過序的區間中值,然後把小於

劃分模板)poj2104

Language: K-th Number Time Limit:20000MS Memory Limit:65536K Total Submissions:37013 Accepted:11911 Case Time Limit:2000MS Description You are wor

POJ2104 K-th Number —— 劃分模板題)

K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 59744 Accepted: 20847 Case Time Limit: 2000MS Descriptio

劃分模板+poj2104)

進入正題: 有這樣一類題目,求的是區間內的第k大數。 劃分樹的定義就是對整體的區間進行劃分,把相對於原來序列中較小的值放在左子樹,較大的放在右子樹,最後按照它的性質進行查詢以此找到要查詢的區間裡的第k大數。 例圖(圖是偷的~~~) 1.建樹 建樹是一個不停遞

NOIP複賽複習(八)STL演算法結構模板

STL演算法 STL 演算法是一些模板函式,提供了相當多的有用演算法和操作,從簡單如for_each(遍歷)到複雜如stable_sort(穩定排序),標頭檔案是:#include <algorithm>。常用STL 演算法庫包括:sort快速排序演算法、二分

演算法模板(五)基礎演算法

最小生成樹 #include<bits/stdc++.h> #define maxn 5000 #define maxm 10000 using namespace std; inline char get(){ static char buf[30],*p1=buf,*p2=buf;

演算法模板(七) 線段

線段樹單點操作 #include<bits/stdc++.h> using namespace std; int a[maxn],sumv[maxn*4]; void pushup(int id){ sumv[id]=sumv[id<<1]+sumv[id<<1

演算法模板】二叉的三種遍歷方式,以及根據兩種遍歷方式建樹

前言:今年九月份的PAT考試就栽在這“兩種遍歷建樹”上了,剛好沒看,剛好考到。作為自己的遺憾,今日碼完,貼在這裡留個紀念,希望能給自己警醒與警鐘。 簡要概括: 1、二叉樹的三種遍歷方式分別是 先序(先根)遍歷PreOrder,中序(中根)遍歷InOrder,後序(後根

劃分詳解+劃分模板程式碼

轉自博主語海與冰 看了一些部落格,感覺有些部落格對建樹寫的挺好,但是對於查詢區間卻一筆帶過。在看懂了之後決定自己寫一篇,加深自己的理解,也希望對正在學習劃分樹的人能夠有所幫助。 如有錯誤,敬請大佬指出。 進入正題: 有這樣一類題目,求的是區間內的第k大數。 劃分樹的定

hdu 2665 Kth number(劃分模板題)

題意:給定一個長度為n的序列,進行m次查詢,求出區間[l,r]中的第k大值。 思路:劃分樹模板題。上學的時候做過這道題,當時看了下劃分樹的講解,看得很頭大,然後就一直放著了。十一回家的時候在高鐵上沒什麼事情,就重新學習了一遍劃分樹。 劃分樹是通過模擬快速排序,記錄快速排序的

POJ 2104 劃分模板

給出n,m n個數字 m次詢問,每次詢問(l,r)區間的第k小的數 劃分樹模板 mark一下 #include "stdio.h" #include "string.h" #include "algorithm" using namespace std; int a[

二叉搜索模板

int ret class get name cnblogs clu space tin #include<cstdio> using namespace std; const int M=9999; struct tr{ int l,r,x,size,nu

hdu 2665 Kth number(劃分

first con build 這一 cst second class stream tom Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth

可持久化線段(主席模板

spa std nod d+ sin 整理 ostream pan int 比賽時候寫的,這裏整理到這裏 #include <iostream> #include <cstdio> #include <cstring> using

POJ 2104 K-th Number(區間第k大數)(平方切割,歸並劃分

ac代碼 deb rank turn tracking line 查看 div 能夠 題目鏈接: http://poj.org/problem?id=2104 解題思路: 由於查詢的個數m非常大。樸素的求法無法在規定時間內求解。因此應該選用合理的方式維護數據來做到高效

BZOJ 2006 NOI2010 超級鋼琴 劃分+堆

heap uil 長度 tdi stream int name -1 找到 題目大意:給定一個序列,找到k個長度在[l,r]之間的序列,使得和最大 暴力O(n^2logn)。肯定過不去 看到這題的第一眼我OTZ了一下午。。。後來研究了非常久別人的題

二叉模板 先序建立 二叉的遍歷 深度

先序遍歷 個數 iostream 葉子節點個數 pop level else 二叉樹的層次遍歷 num 關於二叉樹,基本操作都是在遞歸的基礎上完成的,二叉樹的層次遍歷是隊列實現。具體解釋看代碼 #include<iostream> #include<st

平衡Treap模板與原理

優化 排名 print 比較 pla ans for 後繼 每一個 這次我們來講一講Treap(splay以後再更) 平衡樹是一種排序二叉樹(或二叉搜索樹),所以排序二叉樹可以迅速地判斷兩個值的大小,當然操作肯定不止那麽多(不然我們還學什麽)。 而平衡樹在排序二叉樹的基礎上

HDU 4417 劃分寫法

des eve else eight url ted nta namespace pan Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping ab

hdu 3473 (劃分)2

mage def typedef sin else BE IT ext cati Minimum Sum Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)