日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

划分树

發布時間:2023/12/2 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 划分树 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

昨天的杭電多校聯合訓練熱身賽的一道題,求區間的中位數,快排會超時,劃分樹的模版題。。?

?

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

劃分樹和歸并樹都是用線段樹作為輔助的,原理是基于快排?和歸并排序?的。

劃分樹的建樹過程基本就是模擬快排過程,取一個已經排過序的區間中值,然后把小于中值的點放左邊,大于的放右邊。并且記錄d層第i個數之前(包括i)小于中值的放在左邊的數。具體看下面代碼注釋。


查找其實是關鍵,因為再因查找[l,r]需要到某一點的左右孩子時需要把[l,r]更新。具體分如下幾種情況討論:
假設要在區間[l,r]中查找第k大元素,t為當前節點,lch,rch為左右孩子,left,mid為節點t左邊界和中間點。
1、sum[r]-sum[l-1]>=k,查找lch[t],區間對應為[ left+sum[l-1] , left+sum[r]-1 ]
2、sum[r]-sum[l-1]<k,查找rch[t],區間對應為[ mid+1+l-left-sum[l-1] , mid+1+r-left-sum[r] ]

上面兩個關系在紙上可以推出來,對著上圖更容易理解關系式


POJ 2104 劃分樹模板 ? ?http://poj.org/problem?id=2104


?1?#include?<iostream>
?2?#include?<cstdio>
?3?#include?<algorithm>
?4?using?namespace?std;
?5?#define?N?100005
?6?int?a[N],?as[N];//原數組,排序后數組
?7?int?n,?m;
?8?int?sum[20][N];//記錄第i層的1~j劃分到左子樹的元素個數(包括j)
?9?int?tree[20][N];//記錄第i層元素序列
10?void?build(int?c,?int?l,?int?r){
11?????int?i,?mid?=?(l?+?r)?>>?1,?lm?=?mid?-?l?+?1,?lp?=?l,?rp?=?mid?+?1;
12?????for?(i?=?l;?i?<=?mid;?i++){
13?????????if?(as[i]?<?as[mid]){
14?????????????lm--;//先假設左邊的(mid?-?l?+?1)個數都等于as[mid],然后把實際上小于as[mid]的減去
15?????????}
16?????}
17?????for?(i?=?l;?i?<=?r;?i++){
18?????????if?(i?==?l){
19?????????????sum[c][i]?=?0;//sum[i]表示[l,?i]內有多少個數分到左邊,用DP來維護
20?????????}else{
21?????????????sum[c][i]?=?sum[c][i?-?1];
22?????????}
23?????????if?(tree[c][i]?==?as[mid]){
24?????????????if?(lm){
25?????????????????lm--;
26?????????????????sum[c][i]++;
27?????????????????tree[c?+?1][lp++]?=?tree[c][i];
28?????????????}else
29?????????????????tree[c?+?1][rp++]?=?tree[c][i];
30?????????}?else?if?(tree[c][i]?<?as[mid]){
31?????????????sum[c][i]++;
32?????????????tree[c?+?1][lp++]?=?tree[c][i];
33?????????}?else{
34?????????????tree[c?+?1][rp++]?=?tree[c][i];
35?????????}
36?????}
37?????if?(l?==?r)return;
38?????build(c?+?1,?l,?mid);
39?????build(c?+?1,?mid?+?1,?r);
40?}
41?int?query(int?c,?int?l,?int?r,?int?ql,?int?qr,?int?k){
42?????int?s;//[l,?ql)內將被劃分到左子樹的元素數目
43?????int?ss;//[ql,?qr]內將被劃分到左子樹的元素數目
44?????int?mid?=?(l?+?r)?>>?1;
45?????if?(l?==?r){
46?????????return?tree[c][l];
47?????}
48?????if?(l?==?ql){//這里要特殊處理!
49?????s?=?0;
50?????ss?=?sum[c][qr];
51?????}else{
52?????????s?=?sum[c][ql?-?1];
53?????????ss?=?sum[c][qr]?-?s;
54?????}//假設要在區間[l,r]中查找第k大元素,t為當前節點,lch,rch為左右孩子,left,mid為節點t左邊界和中間點。
55?????if?(k?<=?ss){//sum[r]-sum[l-1]>=k,查找lch[t],區間對應為[?left+sum[l-1],?left+sum[r]-1?]
56?????????return?query(c?+?1,?l,?mid,?l?+?s,?l?+?s?+?ss?-?1,?k);
57?????}else{//sum[r]-sum[l-1]<k,查找rch[t],區間對應為[?mid+1+l-left-sum[l-1],?mid+1+r-left-sum[r]?]
58?????????return?query(c?+?1,?mid?+?1,?r,?mid?-?l?+?1?+?ql?-?s,?mid?-?l?+?1?+?qr?-?s?-?ss,k?-?ss);
59?????}
60?}
61?int?main(){
62?????int?i,?j,?k;
63?????while(~scanf("%d%d",?&n,?&m)){
64?????????for?(i?=?1;?i?<=?n;?i++){
65?????????????scanf("%d",?&a[i]);
66?????????????tree[0][i]?=?as[i]?=?a[i];
67?????????}
68?????????sort(as?+?1,?as?+?1?+?n);
69?????????build(0,?1,?n);
70?????????while(m--){
71?????????????scanf("%d%d%d",&i,&j,&k);//?i,j分別為區間起始點,k為該區間第k大的數。
72?????????????printf("%d\n",?query(0,?1,?n,?i,?j,?k));
73?????????}
74?????}
75?????return?0;

76?}

?

轉載于:https://www.cnblogs.com/pony1993/archive/2012/07/17/2594544.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的划分树的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。