題意就是求區間第k大,不過有修改。
其實這題解法挺多,主席樹套BIT的我之後再寫,這次寫了線段樹套平衡樹的2種解法,第一種是按權值建線段樹套treap,treap裡放的是數的位置,這種方法必須要離線,因為需要把修改的值也一起建樹,第二種則是在線的,按區間建線段樹套treap,treap裡放的是數的大小。第一種建樹復雜度是o(log^2n),詢問復雜度是o(log^2n)。修改復雜度o(log^2n),第二種則差一些,建樹復雜度是o(log^2n),詢問復雜度是o(log^3n),修改復雜度o(log^2n)。
先說第一種,每一個線段樹的節點是那個節點所含treap的根節點,然後查詢的時候,左子樹的含有[L,R]的點如果大於等於k,那麼就到左子樹去查,反之就把K-左子樹[L,R]的點,到右子樹查。一直走到根節點就查到了。修改的時候先刪掉線段樹中原來那個點的值,再插入。
第二種,第二種按照區間建樹,建樹的時候做法基本跟第一種是一樣的。但是要注意有相同數字的問題,導致了treap裡面那個cmp函數有些地方不能用。查詢的時候就有個問題了,肯定是二分最大值也就是10^9,但是有重復值的問題,這樣就導致小於答案的不一定是k-1個,這個問題我是用查詢小於m,以及小於等於m的值來解決的。假設小於m的數有x個,小於等於m的數有y個,x <= k-1 && y>=k
才說明這個值是這個區間裡數且滿足題意。如果不滿足x <= k-1,所以就往小的找,如果不滿足y>=k就往大的找。
按權值建樹:(660ms)
#pragma comment(linker, "/STACK:102400000,102400000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
按區間建樹(1.9s)
#pragma comment(linker, "/STACK:102400000,102400000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include