為什麼我看到一點題解又以為是主席樹
給定乙個整數序列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...