這本來應該是多校的時候用來救命的一道資料結構水題,結果當時不知道是測評機有問題還是我**不夠簡單,15s都tle了,當時很慌,也沒細想,後來重寫了一遍,6s不到過了。
題意很好理解,乙個陣列,我問你某一子區間內所有數和p
pp的差值裡,第k
kk小的是多少?
首先,這題主席樹基本不難想,要是不會主席樹可以參考我以前的部落格:[資料結構——靜態主席樹]
關鍵在於這題建好主席樹之後怎麼辦。當時標程好像是二分列舉k
kk的值,然後看查詢區間在[p−
k,p+
k]
[p-k,p+k]
[p−k,p
+k]範圍內的數個數。
我用的是另一種思路,二分列舉區間左端點。我們注意到,和p
pp距離前k
kk大的數在數值上一定是連續的。主席樹本身就是用來查詢區間第k
kk大的數的,所以,我們可以列舉這段連續區間的左端點,然後+k-1就是右端點,然後比較他們各自與p
pp的差值,如果二者在p
pp兩邊且與p
pp距離相等,那麼此時這就是最優方案。否則,如存在更優狀態,我們把與p
pp距離大的一段向中心移動一定是更優的(注意先更新x
xx的值再移動,因為移動不一定會帶來更優解,若本來就是最優解狀態,可能任何移動都會帶來更差的解)。這樣二分下去就是答案。
上**:
#include
#include
#include
using
namespace std;
const
int maxn =
1e6+10;
int n, q, m, tot;
int a[maxn]
, b[maxn]
, t[maxn]
;int ls[maxn*30]
, rs[maxn*30]
, c[maxn*30]
;void
init()
intbuild
(int l,
int r)
return rt;
}int
update
(int rt,
int pos)
else
c[nw]
= c[rt]+1
;}return res;
}int
query
(int lrt,
int rrt,
int k)
else
}return b[l];}
void
solve()
while
(q--
) e =
query
(t[l]
, t[r+1]
, mid)
, f =
query
(t[l]
, t[r+1]
, mid+k-1)
; x =
min(x,
max(
abs(e-p)
,abs
(p-f)))
;printf
("%d\n"
, x);}
}int
main()
hdu 6621 主席樹 二分
題意 給乙個陣列a,每次詢問,給定l,r,p,k,求 l r 中的數與p做差的絕對值的第k小。思路 對陣列a建立主席樹 不用離散化 對於每次詢問,二分答案,如果 l r 區間中的 p mid p mid 範圍內的數大於k,則說明二分的答案偏大,需要縮小區間 如果等於k,也需要縮小,因為要找到精確的值...
hdu 6621(主席樹模板)
hdu 6621 思路 每次查詢第k小,只有p在改變,所以我們可以列舉p的左右範圍,因為題目中保證每個值都不同,所以省略離散化,直接建立主席樹,二分尋找p的左右範圍,就是最終的答案。include using namespace std const int maxn 1e6 10 int a max...
bzoj2653 二分 主席樹
對於每乙個詢問二分答案。設當前答案為x,將 x的數的權值設為1,當 b 1,c 1 的權值和 a,b 權值和最大的字尾 c,d 權值和最大的字首 0時x可行。先對每個數離散,然後以每個值建立主席樹記錄區間和 最大字首 最大字尾就可以了。時間複雜度 o n log3n 1 include2 inclu...