題意:
給定長度為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...