淺談權值線段樹

#簡介

線段樹大家都知道,不知道的話點這裏。我們線段樹是以標號爲關鍵字的線段樹,顧名思義,權值線段樹就是以權值爲關鍵字的一棵線段樹。其實在實現的時候,比線段樹還簡單,如果你真正理解了線段樹的話~~權值線段樹一般是用來快速求一個區間的第k大(或小),如果你會splay的話請自動點×。

#工作原理
權值線段樹是用來求第k大(或小的)。假設我們由一串數:1,5,2,7,4,6。要你求每次按照順序插入一個數,求當前的第3小,這樣的題目我們就可以用權值線段樹了。假設,我們現在先加入1:
這裏寫圖片描述
我們就在權值爲1的那個點上面加上一,表示它出現了一次。
再加入5:
這裏寫圖片描述
就又在權值爲5的地方加上一,表示它也出現了一次。
然後再看看全部都加進去的情況:
這裏寫圖片描述這就是全部都放進去…
假設,我們在7剛放進去的時候找第3小,就是這樣的情景:
這裏寫圖片描述
首先,我們在根節點,向下去找第3大:
這裏寫圖片描述發現我們左邊只有兩個數,那麼第三大肯定在右邊,那我們就走右邊:
這裏寫圖片描述然後,我們就要減去左邊的2,就表示我們本來第三小,現在在右邊找最小的就好了。
那麼,就知道,當前的左兒子就有一個,那麼剛好滿足條件,就進去,我們就找到啦!!
這裏寫圖片描述答案就是5啦!
是不是很有味道,其實實現起來也不難。
我們那一道例題吧!
#例題
#黑匣子
Description
Black Box是一種原始的數據庫。它可以儲存一個整數數組,還有一個特別的變量 i 。最開始的時候Black Box是空的,而 i 等於 0。這個 Black Box 要處理一串命令。
命令只有兩種:
ADD(x): 把 x 元素放進 Black Box;
GET: i 加 1 ,然後輸出 Black box 中第 i 小的數。
記住:第 i 小的數,就是 Black Box裏的數的按從小到大的順序排序後的第 i 個元素。
例如
我們來演示一下一個有11個命令的命令串。
這裏寫圖片描述
現在要求找出對於給定的命令串的最好的處理方法。ADD 和 GET 命令分別最多有200000個。
現在用兩個整數數組來表示命令串:

  1. A(1), A(2), …, A(M): 一串將要被放進Black Box的元素。每個數都是絕對值不超過2000000000的整數,M <=200000。例如上面的例子就是A=(3, 1, -4, 2, 8, -1000, 2).
  2. u(1), u(2), …, u(N): 表示第u(j)個元素被放進了Black Box裏後就出現一個GET命令。例如上面的例子中u=(1, 2, 6, 6)。 輸入數據不用判錯。
    Input
    第一行,兩個整數,M,N,
    第二行,M個整數,表示A(1)……A(M),
    第三行,N個整數,表示u(1)……u(N)。
    Output
    輸出 Black Box 根據命令串所得出的輸出串,一個數字一行。
    Sample Input
    7 4
    3 1 -4 2 8 -1000 2
    1 2 6 6
    Sample Output
    3
    3
    1
    2
    Data Constraint
    【數據規模】
    對於30%的數據,M<=10000;
    對於50%的數據,M<=100000;
    對於100%的數據,M<=200000。
    這道題其實就是一道裸的權值線段樹,我不多說了,自己看看標程吧!
var
        a,b,al,bz,wz,wz1:array[0..200000]of longint;
        f,fy:array[0..262129]of longint;
        n,i,t,m,nn,j,k,len:longint;
procedure kp(l,r:longint);
var
        i,j,mid:longint;
begin
        i:=l;
        j:=r;
        mid:=a[l];
        while i<=j do
        begin
                while a[i]<mid do inc(i);
                while a[j]>mid do dec(j);
                if i<=j then
                begin
                        a[0]:=a[i];
                        a[i]:=a[j];
                        a[j]:=a[0];
                        wz[0]:=wz[i];
                        wz[i]:=wz[j];
                        wz[j]:=wz[0];
                        inc(i);
                        dec(j);
                end;
        end;
        if l<j then kp(l,j);
        if r>i then kp(i,r);
end;
procedure make(v,l,r,x:longint);
var
        mid:longint;
begin
        mid:=(l+r) div 2;
        if l=r then
        begin
                inc(f[v]);
                fy[v]:=a[bz[l]];
                exit;
        end
        else
        begin
                if x<=mid then make(v*2,l,mid,x);
                if x>mid then make(v*2+1,mid+1,r,x);
        end;
        f[v]:=f[v*2]+f[v*2+1];
end;
function find(v,l,r,k:longint):longint;
var
        mid:longint;
begin
        mid:=(l+r) div 2;
        if l=r then exit(fy[v])
        else
        begin
                if k<=f[v*2] then exit(find(v*2,l,mid,k));
                if k>f[v*2] then exit(find(v*2+1,mid+1,r,k-f[v*2]));
        end;
        f[v]:=f[v*2]+f[v*2+1];
end;
begin
        readln(n,m);
        for i:=1 to n do
        begin
                read(a[i]);
                wz[i]:=i;
        end;
        for i:=1 to m do
                read(b[i]);
        kp(1,n);
        j:=0;
        for i:=1 to n do
                if a[i]<>a[i-1] then
                begin
                        inc(j);
                        al[i]:=j;
                        bz[j]:=i;
                        wz1[wz[i]]:=i;
                end
                else
                begin
                        al[i]:=al[i-1];
                        wz1[wz[i]]:=i;
                end;
        len:=j;
        j:=1;
        k:=0;
        for i:=1 to n do
        begin
                make(1,1,len,al[wz1[i]]);
                while b[j]=i do
                begin
                        inc(k);
                        inc(j);
                        writeln(find(1,1,len,k));
                end;
        end;
end.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章