#簡介
線段樹大家都知道,不知道的話點這裏。我們線段樹是以標號爲關鍵字的線段樹,顧名思義,權值線段樹就是以權值爲關鍵字的一棵線段樹。其實在實現的時候,比線段樹還簡單,如果你真正理解了線段樹的話~~權值線段樹一般是用來快速求一個區間的第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個。
現在用兩個整數數組來表示命令串:
- A(1), A(2), …, A(M): 一串將要被放進Black Box的元素。每個數都是絕對值不超過2000000000的整數,M <=200000。例如上面的例子就是A=(3, 1, -4, 2, 8, -1000, 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.