搜尋關於劃分樹的講解,竟然搜到了鄭大媛學姐的博文,不是這篇
原博文有錯誤,我就不給出原鏈結了
用劃分樹來解決選定區間內的第k大值,其實也就兩步!一步是建樹,另一步則是查詢。
先說我對建樹的理解吧!
建樹的過程很簡單:兩步就ok了!
第一步:找到序列的中位數,把大於中位數的扔到中位數的左邊,小於中位數的扔到數的右邊。這樣整個序列就被分成了兩個區間。
第二步:對每個子區間,也分別執行第一步操作,直到序列中只有乙個元素為止。
可以看出,建樹是乙個遞迴的過程,與線段樹的建樹有相似之處。
劃分樹的建樹需要注意以下幾點:
第一:建樹是分層的,所以**中用的是二維陣列tree[20][m]。一般10w級別的資料,20層已經夠了。
第二:建樹劃分的標準是中位數,所以需要排序。而且只排一次序就ok了,為什麼只排一次就ok了,我很久都沒明白這一點。其實是這樣的:對於任意序列: 劃分後,左邊的資料永遠不會大於右邊的資料。那麼對左邊資料單獨排序與整體排序的結果是一樣的,所以排一次序就ok了!
第三:劃分樹劃分好的資料永遠在存放在下一層。比如資料:
tree[0][m]=1 5 2 6 3 7 4
排序後為:1 2 3 4 5 6 7
中位數為:4
劃分後的結果為:tree[1][m]=1 2 3 4 5 6 7(這組資料有點特殊,劃分後來就已經是排好序的了)紅黑色字型都仍按原未排順序排列
(紅色表示劃分到中位數的左邊,黑色表示劃分到中位數的右邊)
接著劃分:tree[2][m]=1 2 3 4 5 6 7
再接著分:tree[3][m]=1 2 3 4 5 6 0
到這裡已經分完了,為什麼最後是0呢?在第2層(tree[2][m]),7已經分完了,所以不用再分
第四:劃分到最後,實際上已經對序列進行排序了。
劃分的時候還有一點需要處理:如果有多個資料相同怎麼辦呢?通過一種特殊的處理:盡量使左右兩邊平均分配相同的數。這個特殊處理是這樣的:
在沒分之前,先假設中位數左邊的資料suppose都已經分到左邊了,所以suppose=mid-left+1;然後如果真的分在左邊,即if(tree[level][i]
suppose--;suppose就減一!到最後,如果suppos=1,則說明中位數左邊的數都小於中位數,如果有等於中位數的,則suppose大於1。
最後分配的時候,把suppose個數,分到左邊就可以了,剩下的分到右邊!因為suppose的初值是mid-left+1,這樣就能保證中位數左邊和右邊的數平衡了!
第五:劃分的過程,需要把每層的資料記錄:toleft[20][m]。toleft[i][j]定義為:第i層[l,j]之間有多個資料被分到了左邊(注意這裡用的是閉區間)
模板:[cpp]view plain
copy
print?
#include
#include
using
namespace
std;
#define m 100005
inttree[20][m],sorted[m];
inttoleft[20][m];
void
build(
intlevel,
intleft,
intright)
}
/*如果suppose==1,則說明陣列中值為sorted[mid]只有乙個數。
比如序列:1 3 4 5 6,sorted[mid]=4
*//*如果suppose>1,則說明陣列中左半邊值為sorted[mid]的不止乙個數,為mid-suppose。
比如序列:1 4 4 4 6,sorted[mid]=4
*/int
lpos=left,rpos=mid+1;
for(i=left;i<=right;i++)
else
if(tree[level][i]
//劃分到中位數左邊
toleft[level][i]++;
tree[level+1][lpos++]=tree[level][i];
} else
if(tree[level][i]>sorted[mid])
else
else
}
}
build(level+1,left,mid);
build(level+1,mid+1,right);
}
//在[left,right]資料中查詢[qleft,qright]中第k大的資料
intquery(
intlevel,
intleft,
intright,
intqleft,
intqright,
intk)else
intnewl,newr;
if(k<=ss)
else
}
intmain()
sort(sorted+1,sorted+n+1);
build(0,1,n);
intql,qr,k;
for(i=0;i
scanf("%d %d %d"
,&ql,&qr,&k);
printf("%d\n"
,query(0,1,n,ql,qr,k));
}
}
return
0;
}
劃分樹小結
最近學習了一下劃分樹,下面總結一下。我們在求區間最值的時候,一般可以用線段樹解決,但是如果要求區間第k小或者第k大值的話線段樹就有點力不從心了,這是我們可以用劃分樹來解決。劃分樹利用了快速排序的思想,首先是建樹,我們設當前區間的中位數為mid,為了能快速找到區間的中位數,我們一般先對原序列做一次排序...
劃分樹詳解
題目 給出n個數,和m個區間 對於每個區間 l r 輸出這個區間裡面第k大的數。我們來看看劃分樹是怎麼構造的。構造 以2104為例子,舉2 0 6 8 5 1 4 3 9為例子,構造劃分樹是這樣的 上面的內容是用乙個二位陣列val儲存下來的,第一維表示劃分樹的第幾層,第二位表示在這一層中的位置。要注...
劃分樹模板
border 0 width 330 height 86 src upd 3.17 複習了一些劃分樹 做了一下簡單的複習筆記 傳到雲上了qaq 恩 打了半小時 恩 213的把瀏覽器關掉了 恩 心好累 不打劃分樹的詳細解釋了 粘三份 好了 第乙份是t的 蒟蒻捂臉 的我 沒學劃分樹的最好看一下 對理解後...