P3834 (靜態區間第k大,整體二分)

2021-10-09 04:52:05 字數 1693 閱讀 7425

題意:

給定長度為n的序列a,m次詢問,每次詢問給出l,r,k,要求計算[l,r]的第k小數

資料範圍:n,m<=2e5,-1e9<=a(i)<=1e9

解法:整體二分的主要思想:

對需要在值域[l,r]內二分的所有詢問,共用乙個二分,相比每個詢問於單獨二分,減少了二分總次數

整體二分是離線演算法。

需要注意的點:

二分的值域存在負數,二分需要寫mid=(l+r)>>1,而不能是mid=(l+r)/2

原因:正數二分,[1,6]分為[1,3]和[4,6],因為(1+6)/2=3

負數二分,[-6,-1]會分為[-6,-3]和[-2,-1],因為(-6±1)/2=-3

發現負數二分,區間大小並不是均分的,正確的應該是[-6,-4]和[-3,-1]

因為多了乙個符號,"向下取整"變成"向上取整"了,所以會錯

正確做法是用位運算》1,這樣就對了(負數是對補碼右移,而正數的補碼就是原碼,不一樣)

ps:利用樹狀陣列離線的演算法,好像常常會將bit存值變為bit存下標。

code:

#include

using

namespace std;

const

int maxm=

2e5+10;

struct qq[maxm<<1]

,q1[maxm<<1]

,q2[maxm<<1]

;//q1:[l,mid],q2:[mid+1,r]

int cnt;

int ans[maxm]

;int n,m;

//bit

int c[maxm]

;int

lowbit

(int i)

void

add(

int i,

int t)

}int

ask(

int i)

return ans;}//

void

solve

(int l,

int r,

int l,

int r)

}return;}

int mid=

(l+r)

>>

1,cnt1=

0,cnt2=0;

for(

int i=l;i<=r;i++

)else

}else

else}}

for(

int i=

1;i<=cnt1;i++

)for

(int i=

1;i<=cnt1;i++

)for

(int i=

1;i<=cnt2;i++

)solve

(l,mid,l,l+cnt1-1)

;solve

(mid+

1,r,l+cnt1,r);}

signed

main()

;}for(

int i=

1;i<=m;i++);

}solve(-

1e9,

1e9,

1,cnt)

;for

(int i=

1;i<=m;i++

)return0;

}

靜態主席樹(區間第k小) 洛谷P3834

時間限制1.00s 1.20s 記憶體限制125.00mb 250.00mb 這是個非常經典的主席樹入門題 靜態區間第k小 資料已經過加強,請使用主席樹。同時請注意常數優化 如題,給定n個整數構成的序列,將對於指定的閉區間查詢其區間內的第k小值。第一行包含兩個正整數n m,分別表示序列的長度和查詢的...

複習 整體二分求區間第K大

給定乙個長度為n的序列與m個 l,r,k 詢問區間 l,r 中第k大。考慮單個詢問的解決,我們可以二分答案然後統計比他大的數的個數。那麼時間複雜度就是n log m.但多個詢問如何解決?我們可以整體地二分答案區間 l,r 然後將詢問集合分割,分到 l,mid 與 mid 1,r 的子分治過程中處理。...

靜態區間第K小(整體二分 主席樹)

題目鏈結 題解主席樹入門題 但是這裡給出整體二分解法 整體二分顧名思義是把所有操作放在一起二分 想想,如果求 1 n 的第 k 小怎麼二分求得?我們可以二分答案 k o n 統計有多少個數小於等於 k 如果對於每個詢問都這麼搞,肯定不行 我們可以發現,如果每次都搞一次,有許多算重複的地方 div l...