第k大區間和問題的樹狀陣列實現

2021-06-27 01:58:52 字數 2560 閱讀 4086

為什麼我看到一點題解又以為是主席樹

給定乙個整數序列a[1..n],定義sum[i][j]=a[i]+a[i+l]+……+a[j],將所有的sum[i][j]從小到大排序(其中i,j滿足1<=i<=j<=n),得到乙個長為n*(n+1)/2的序列,求該序列中的第k個元素。

輸入格式(ktm.in)

第一行有兩個整數n,k,其中0接下來n行每行乙個整數。順序給出序列a的元素。

輸出格式(kth.out)                       

sum序列中的第k個元素

題解:這道題據說是noip難度的,如果noip真的考這個我就可以直接退役了.

我講這道題主要是想講如何用樹狀陣列來代替平衡樹的部分功能,從而節省**量.

演算法是很顯然的:首先二分答案.假設答案為k,我們求出所有sum中小於k的個數就行了.演算法的瓶頸在於什麼找到所有sum中有多少小於k.

先講講平衡樹的做法:預處理乙個s陣列,s[i]表示sum[0,i].依次加入s[i],統計s1~s[i-1]中大於s[i]-k的個數即可.利用乙個平衡樹就可以很簡單的做到這些操作.

然而,平衡樹不僅**量較大且常數很高,所以我們考慮利用其他資料結構來實現這一功能.

這個資料結構要支援兩種操作:加入:加入乙個元素;查詢:查詢所有元素中比k小的元素個數.

這個東西貌似只有平衡樹之類的高階資料結構能做,但是,我們可以只用乙個樹狀陣列就實現這些功能.

我們先將所有的s值排序.首先按原先的次序依次加入si.先將插入操作.插入時直接將si當前對應的下標置為1即可(初值為0).而加入si前,我們要查詢在si之前的元素中大於si-k的個數.我們可以先在s中二分出乙個p,使s[p]之前的元素都大於si-k,然後求出1~p中的字首和即可.字首和可以用樹狀陣列維護.

這個方法雖然多了乙個二分操作和乙個排序.但是排序相信大家都能在5分鐘內搞出來.至於二分也非常簡單.而樹狀陣列的**量遠小於平衡樹,並且幾乎不會打錯,所以這個方法還是很實用的.至於時間複雜度,雖然演算法多了乙個二分的複雜度log(n),但不要忘記,樹狀陣列的常數遠小於平衡樹,空間消耗也非常小.所以這種處理方式不會差與平衡樹,甚至在某些情況下比平衡樹更優.

下面是我的**

program kth;

type

int=longint;

var i,j,k,m,n:int;

s,f,p,rank:array[0..100000]of int;

x,y,z:int;

procedure swap(var x,y:int);var t:int;

begin

t:=x;x:=y;y:=t;

end;

procedure sort(l,r:int);var i,j:int;

begin

i:=l;j:=r;

x:=s[l+random(r-l)];

repeat

while s[i]>x do inc(i);

while s[j]j;

if il then sort(l,j);

end;

function ask(x:int):int;var i:int;

begin

ask:=0;i:=1;

while i<=x do begin

while i+(i and -i)<=x do i:=i+(i and -i);

inc(ask,f[i]);inc(i);

end;

end;

procedure ins(x:int);

begin

while x<=n do begin

inc(f[x]);x:=x+(x and -x);

end;

end;

function get(min:int):int;var l,r,mid,i:int;

begin

l:=1;r:=n;

while r-l>3 do begin

mid:=(l+r)>>1;

if s[mid]>=min then l:=mid

else r:=mid;

end;

for i:=l to r do if(s[i-1]>=min)and(s[i]=m then r:=mid

else l:=mid;

if r-l<10 then begin

for i:=l-1 to r do begin

k:=sum(i);

if k>=m then exit(i);

end;

end;

end;

end;

begin

read(n,m);s[0]:=0;

for i:=1 to n do begin

read(x);s[i]:=s[i-1]+x;rank[i]:=i+1;

end;

inc(n);s[n]:=0;rank[n]:=1;

sort(1,n);s[0]:=maxlongint;

for i:=1 to n do p[rank[i]]:=i;

write(ans);

end.

第k大區間和問題的樹狀陣列實現

給定乙個整數序列a 1.n 定義sum i j a i a i l a j 將所有的sum i j 從小到大排序 其中i,j滿足1 i j n 得到乙個長為n n 1 2的序列,求該序列中的第k個元素。輸入格式 ktm.in 第一行有兩個整數n,k,其中0接下來n行每行乙個整數。順序給出序列a的元素...

51nod 第K大區間2(二分 樹狀陣列)

定義乙個長度為奇數的區間的值為其所包含的的元素的中位數。現給出n個數,求將所有長度為奇數的區間的值排序後,第k大的值為多少。樣例解釋 l,r 表示區間的值 1 3 2 1 3 2 4 4 1,3 2 2,4 2 第三大是2 input第一行兩個數n和k 1 n 100000,k 奇數區間的數量 第二...

動態區間第K大 樹狀陣列 主席樹

很早以前做靜態第k大的時候聽到要用樹套樹就過於害怕逃走了,現在用分塊暴力過了之後又想用樹套樹a一遍,於是就寫了一下 starkmal的線段樹 splay常數卡出翔惹 prag ma gcc optimize o3 include include include include include inc...