求區間第K小值的兩種解法 POJ2761

2021-09-03 08:49:32 字數 3080 閱讀 8781

前幾天學習了劃分樹和sbt,一直沒機會訓練一下,今天實驗室有網了,就訓練poj上面一道水題。分別用兩種資料結構來實現了一下!

這道題題目很簡單,就是給定序列,求區間最小值!

sbt:

#include

#include

using

namespace std; 

#define m 100005

struct sbttree[m]; 

int root,top; 

int a[m]; 

struct queryque[m/2]; 

bool cmp(const query &q1,const query &q2) 

return q1.ql} 

bool cmp2(const query &q1,const query &q2) 

void init() 

//這兩種旋轉看起來是挺容易的,但自己寫容易混亂,最好能結合圖

void rotate_left(int &x) 

void rotate_right(int &x) 

void maintain(int &x,bool flag)else

if(tree[tree[tree[x].left].right].size>tree[tree[x].right].size)else

return ; 

}elseelse

if(tree[tree[tree[x].right].left].size>tree[tree[x].left].size)else

return ; 

} maintain(tree[x].left,false); 

maintain(tree[x].right,true); 

maintain(x,false); 

maintain(x,true); 

} /*

* 這裡用陣列實現,遞迴插入,挺巧妙的,我自己用陣列做的時候都不會想到這樣做

* tree的0位置空著不用; 帥氣,如果不進行調整的話,root能保持root=1

* */

void insert(int &x,int key)else 

} //這裡要保證刪除的資料存在

void remove(int &x,int key)else

if(keyremove(tree[x].left,key); 

}elseelse

if(tree[x].right!=0&&tree[x].left==0)else

if(tree[x].left==0&&tree[x].right==0)else 

} } 

//求第k小的數

int select(int &x,int k) 

int main() 

int ql,qr,k; 

for(i=0;iscanf("%d %d %d",&ql,&qr,&k); 

que[i].id=i; 

que[i].k=k; 

que[i].ql=ql; 

que[i].qr=qr; 

} sort(que,que+m,cmp); 

for(i=que[0].ql;i<=que[0].qr;i++) 

que[0].ans=select(root,que[0].k); 

for(i=1;i//前乙個區間與當前區間只有兩種關係,相交或者不相交

if(que[i].ql<=que[i-1].qr) 

} //看終點

if(que[i].qr//

for(j=que[i].qr+1;j<=que[i-1].qr;j++) 

}else

if(que[i].qr>que[i-1].qr) 

} }else 

for(j=que[i].ql;j<=que[i].qr;j++) 

} que[i].ans=select(root,que[i].k); 

} sort(que,que+m,cmp2); 

for(i=0;iprintf("%d\n",que[i].ans); 

} return 0; } 

劃分樹:

#include

#include

using

namespace std; 

#define m 100005

int tree[30][m]; 

int toleft[30][m]; 

int sorted[m]; 

int n,m; 

void build(int level,int left,int right) 

} 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])elseelse 

} } 

build(level+1,left,mid); 

build(level+1,mid+1,right); 

} int query(int level,int left,int right,int ql,int qr,int k) 

int s,ss; 

int mid=(left+right)>>1; 

if(left==ql)else 

int nql,nqr; 

if(k<=ss)else 

return 0; 

} int main() 

sort(sorted+1,sorted+n+1); 

build(0,1,n); 

int ql,qr,k; 

for(int i=0;iscanf("%d %d %d",&ql,&qr,&k); 

int ans=query(0,1,n,ql,qr,k); 

printf("%d\n",ans); 

} return 0; } 

求素數的兩種解法

檔名 exp1 1.cpp 求素數的個數 include include bool prime int n 判斷正整數n是否是素數 int main for i 3 i n i 2 printf n return 0 檔名 exp1 1 2.cpp 利用快速篩選法求素數的個數 篩法的思想是去除要求範...

主席樹,查詢區間的第k小值

學習報告 主席樹真的nb,如果樸素做要開n個線段樹,記憶體 優化的方式,每次插入乙個數,並不是整個權值線段樹都改變了,只是改變logn個節點,我們只需要多開logn個節點就ok,用root陣列記錄歷史個線段樹版本,詢問區間,可以做相減,詢問第k小值,與左樹的所有節點sum作比較,如果小就在左邊,否則...

「取最大的K的數」的兩種解法

輸入n個整數,輸出其中最大的k個。例如輸入1,2,3,4,5,6,7和8這8個數字,則最小的4個數字為5,6,7和8。開乙個容量為k的最小堆。每次來乙個數,比較堆頂 最小值 和這個數誰大,如果當前的數更大,就替換掉堆頂。時間複雜度 o nlogk 優點 對於海量資料 流 可以用o k 的記憶體搞定 ...