Tải bản đầy đủ (.pdf) (89 trang)

Một Số Cấu Trúc Dữ Liệu Đặc Biệt

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (2 MB, 89 trang )

Cây quản lý phạm vi

 này gii thiu cây qun lý phm vi (range trees). t cu trúc d
liu quan trng, có nhiu ng dng trong các thut toán hình hc, truy v d
liu và x lý tín hiu. Cây qun lý ph    cp nhiu trong các k thi
olympic tin hc trong kho l
1. Giới thiệu
Gi s ta có m d liu cha h a các nhân viên trong mt
công ty, thông tin v mi nhân viên là mt bn ghi gm nhia
chp b  d liu này luôn bing bi các
lnh thêm/bt/cp nht b    i truy vn d  m s
i    tui t 40 ti 50 và có m tháng t 3 triu ti 5
triu  Tính ta nhi có thâm niên công tác t 10
 lên và có t 2 ti 4 con
Dng bài toán qung và tr li các dng truy vn k trên có th mô
i dng hình hc: Chng hn ta có th biu din mi nhân viên bi
mm trên mt phng t  vi trc t  là tui và trc t
 là mm s  tui t 40 ti
50 và có m 3 ti 5 tri din gii thành: m s m
có t













(Xem Hình 1)



Hình 1
Bài toán truy vn phm vi có th phát biu hình thn qun lý
mt tp  các ng biu din bi các m trong không gian  chiu, mi
m ngoài t ca nó còn có th cha thêm mt s thông tin khác
*
. Tp 
liên tc bing bi phép thêm/bi các truy vn. Mi truy
vn, cho bi phm vi là mt siêu hp  













 







,
yêu cu tr li v thông tin tng hp t tt c m nm trong siêu hp .
 này, ta quan tâm ti các dng thông tin tng hp có tính cht
 trc là nu  và  là hai tm ri nhau thì thông tin tng hp
t m    có th d c t thông tin tng hp trên  và
thông tin tng hp trên  v  d liu nhân s, ta có th d
c:
 S i trong tp    bng cách ly s i trong  cng s i
trong .
 a nt trong tp   , 

  

 có th
nh bng công thc 










S u tp  ch g lc tt c
nhm nm trong phm vi truy vn và tng hp thông tin t nhm

 m ln, mc dù phép thêm bm có th thc hin



*
Trong CSDL quan h, mt s ct s nh làm t và nhng ct còn li s c coi là thông tin cn
truy vn tùy theo tng ng dng c th.
Ο


40
50
3.000.000
5.000.000
nhanh (thi gian 



nu s dng cu trúc d ling),
thi gian truy vn tr nên rt chm (mt 



thi gian  tr li mi
truy vn vi  là s m trong  và  là s chiu ca không gian).
Cây qun lý phm vi là mt cu trúc d liu hiu qu  gii quyt bài toán
trên, nó cho phép thc hin mi phép thêm, bt, cp nht, truy vn trong thi
gian 






, thích hp vi x lý d liu lng 

t
chm so vi ng 



khi 
Trong các phn tip theo, phn 2 kho sát mt s cu trúc d liu và thut
toán gii quyt bài toán truy vn phm vi 1 chiu. Phn 3 m rng các cu
trúc d liu cho truy vn phm vi nhiu chiu. Phn 4 là mt s bài toán ng
dng, m rng ca cây qun lý phm vi, cui cùng là kt lun và danh mc tài
liu tham kho.
2. Truy vấn phạm vi một chiều
2.1. Cây nhị phân tìm kiếm
t nh biu din danh sách là s dng mng
hoc danh sách móc ni. S dng mng có t tt vi phép truy cp ngu
nhiên   b chm nu danh sách luôn b bi ng bi các phép
 dng danh sách móc ni có th thun ti
trong các phép chèn/xóa thì li g  m trong phép truy cp ngu
nhiên.
Trong mc này chúng ta s trình bày mu din danh sách
bng cây nh p ngu nhiên, chèn, xóa và truy
vn c thc hin trong thi gian 




. N
c trình bày qua mt bài toán c th:
Bài toán (Range Query):
Cho mt danh sách   cha các s nguyên. Ký hiu 



là s phn t
trong danh sách. Các phn t  liên tip bu
t 1.
Bu vi mt danh sách rng, xét các phép bii danh sách 


 Phép chèn 



: Chèn mt s  vào v trí  ca danh sách. ng
hp 



thì  s c thêm vào cui danh sách.
 Phép xóa 



: Xóa phn t th  trong danh sách.
 Phép cp nht 




: t phn t th  bng .
 Phép truy vn 



: Tr v tng các phn t nm trong phm vi t 
ti 
Yêu cu: Cho dãy  phép bic thc hin tun t, hãy tr li tt c các
truy vn 
Input
 Dòng 1 cha s 


  dòng tip, mi dòng cho thông tin v mt phép bii. Mi dòng bt
u bi mt ký t 




 Nu ký t u dòng là thì tip theo là hai s nguyên  ng
vi phép chèn 



(

)
 Nu ký t u dòng là thì tip theo là s nguyên  ng vi

phép xóa 



.
 Nu ký t p theo là hai s nguyên  ng
vi phép cp nht 



(

)
 Nu ký t p theo là hai s nguyên  ng
vi phép truy vn 



()
Output
Tr li tt c các truy vn , vi mi truy vn in ra câu tr li trên 1 dòng
Sample Input
Sample Output
11
I 1 8 {8}
I 1 3 {3 8}
I 3 6 {3 8 6}
I 3 2 {3 8 2 6}
Q 1 3
U 3 4 {3 8 4 6}

I 2 5 {3 5 8 4 6}
D 1 {5 8 4 6}
Q 2 4
U 1 7 {7 8 4 6}
Q 1 4
13
18
25

2.1.1. Biểu diễn danh sách
Chúng ta s  các phn t ca danh sách  trong mt cu trúc cây nh
phân sao cho nu duyt cây theo thứ tự giữa thì các phn t ca  s c lit
 t trong danh sách. Cây nh t bi mt
cu trúc liên kng và con trng chính ca cách tip cn này
là đồng bộ thứ tự của danh sách trừu tượng  với thứ tự giữa của cây, quy việc
chèn xóa trên  về việc chèn xóa trên cây nhị phân.
Có mt s  ng gia cu trúc d liu này và cây nh phân tìm
kim (binary search trees – BST):
 Nu danh sách trng  gm các phn t p xn thì t
nhiên cây biu din danh sách tr thành cây nh phân tìm kim.
 Nu duyt cây nh phân tìm kim theo th t gin
các khóa tìm kim, còn nu duyt cây biu din danh sách theo th t
gia ta s c danh sách .
 Có th có nhiu cu trúc cây nh phân tìm kim ng vi mt tp khóa tìm
ki y có nhiu cu trúc cây biu din danh sách ng vi
danh sách .
 ng cây biu din danh sách có th k tha t cây
nh phân tìm kim bi các k thut cân bng cây nh phân tìm kim luôn
bo tn th t gia cng vi th t n ca các
khóa tìm king b th t danh sách vi th t

gia ca các nút trên cây ch không phi là th t c hay th t sau.
Chính vì có nhing gia cu trúc cây biu din danh sách và
cây nh phân tìm kim, tcây nh phân tìm kim  binary search
trees (BST) cho cu trúc d liu này.
2.1.2. Cấu trúc nút
Có th thy rng khi duyt cây theo th t gia thì các nút mt nhánh cây s
c lit kê trong mn liên tip, không có nút  nhánh khác xen vào. Nói
cách khác, bn cht mi nhánh cây là mn các phn t liên tip trong
danh sách trng . i ý cho vi thêm nhng thông tin
tng hp v n liên tip này ti nhng mng hp


c th này, mi nút  s cha thêm 2 thông tin: S nút trong nhánh gc 
  thc hin phép truy cp ngu nhiên) và tng các phn t trong
nhánh gc   tr li truy vn tng).
Tóm li, mi nút trên cây là mt bn ghi gng:
 ng : Cha phn t 
 ng  Cha liên kt (con tr) ti nút cha, nu là nút gc (không có nút
ng  t bng mt con tr c bit, ký hiu .
 ng : Cha liên kt (con tr) ti nút con trái, nu nút không có nhánh
con trái thì tng  t bng .
 ng : Cha liên kt (con tr) ti nút con phi, nu nút không có
nhánh con phng  t bng .
 Trng  cha s nút trong nhánh gc 
 ng  cha tng phn t cha trong nhánh gc 

Hình 2. Cây biu din danh sách gm 7 phn t (1, 7, 3, 6, 5, 4, 2)
 

 

1
 
 
7

 
3
 
 
6
 
 
5


4

 
2
type
PNode = ^TNode;
//Kiểu con trỏ tới một nút
TNode = record
key: TKey;
P, L, R: PNode;
len: Integer;
sum: Int64;
end;
var
sentinel: TNode;

nilT: PNode;
//Con trỏ tới nút đặt biệt
root: PNode;
//Con trỏ tới nút gốc
begin
nilT := @sentinel;
nilT^.size := 0;
nilT^.sum := 0;

end.

Các ngôn ng lp trình bng cung cp hng con tr  (hay 
gán cho các liên kt không tn ti trong cu trúc d liu. Hng con tr  ch
c s dng  so sánh vi các con tr c phép truy cp bin
ng .
t cây nh phân, chúng ta s dng con tr  gán cho nhng liên
kt không có thc (công d  ). Ch có khác là con tr
 tr ti mt bin  có thực m   ng ca  là vô
nghĩa. Chúng ta hy sinh mt ô nh cho bin   n hóa
các thao tác trên cây
*
.
Th tc 



ng hp các thông tin trong  t nhng thông tin
ph tr trong hai nút con:

procedure Update(x: PNode);

begin
x^.len := x^.L^.len + x^.R^.len + 1;
//Tính số nút trong nhánh x
x^.sum := x^.L^.sum + x^.R^.sum + x^.value;
//Tính tổng các phần tử trong nhánh x
end;

 c  và .
 d trình bày các thao tác, ta vit sn các th tc móc ni các nút: Th tc




cho  làm con trái , th tc 



cho  làm con phi 



*
Ma bi bm tra con tr  c khi truy cp nút .



procedure SetL(x, y: PNode);
begin
y^.P := x; x^.L := y;
end;


procedure SetR(x, y: PNode);
begin
y^.P := x; x^.R := y;
end;

2.1.3. Truy cập ngẫu nhiên
C các phép biu có mt tham s v trí, vy viu tiên là
phng vi v trí  trong danh sách trng là nút nào
trong cây. Theo nguyên lý ca phép duyt cây theo th t gia (duyt nhánh
t nhánh phi), thu
ng vi v trí  có th din t 
 tìm nút th  trong nhánh cây gc c hnh  là s th t
ca nút gc  (theo th t gia):  
 Nu  thì nút cn tìm chính là nút .
 Nu  thì quy v tìm nút th  trong nhánh con trái ca .
 Nu  thì quy v tìm nút th  trong nhánh con phi ca .
S c l ng vi v trí  có th tính b sâu ca nút
kt qu cng thêm 1. Phép truy cp ng    t bng hàm




: Nhn vào nút  và mt s nguyên , tr v ng vi v
c .

function NodeAt(x: PNode; i: Integer): PNode;
var
ord: Integer;
begin

repeat
ord := x^.L^.len + 1;
//Xác định số thứ tự nút x
if ord = i then Break;
//Nút cần tìm chính là x
if i < ord then
//Quy về tìm nút thứ i trong nhánh con trái
x := x^.L
else
//Quy về tìm nút thứ i – ord trong nhánh con phải
begin
i := i - ord;
x := x^.R;
end;
until False;
Result := x;
end;

2.1.4. Vấn đề cân bằng cây
Thao tác truy cp ngu nhiên thc hin mt phép di chuyn t gc xung mt
nút mang s th t nh, nu cây nh phân suy bin, phép truy cp ngu
nhiên không khác gì phép truy cp tun t trên danh sách móc ni  và tr
nên kém hiu qu. Rt may mn là ta có nhbng cây.
Nhc gi cho chiu cao cây là mng 




vi  là s nút trên cây, hom bo cho dãy  thao tác truy cp ngu nhiên
c thc hin trong thi gian 




. Nh   
bc k tha t các cu trúc d liu cây nh phân tìm kim t cân
bng (self-balancing binary search trees 
Treaps, cây nh phân tìm kim ng
Hu ht các k thut cân bc thc hin bi phép quay cây, có hai
loi: quay phi (right rotation) và quay trái (left rotation).
 Nu  là con trái ca , phép quay phi theo liên kt  ct nhánh con
phi ca  làm con trái ca   làm con phi ca . Nút  c
y lên làm gc nhánh thay cho nút     Hình 3, có th thy
rng phép quay phi bo tn th t gia .


 c li, nu  là con phi ca , phép quay trái theo liên kt  vi 
ct nhánh con trái ca  làm con phi ca   làm con trái ca
 y  lên làm nút nhánh
thay cho nút   Hình 3 thy rng phép quay trái
bo tn th t gia      .

Hình 3. Phép quay cây
Ta vit mt thao tác 



t   i , và ,
phép 




s quay theo liên kt   y nút  lên phía gc cây
 sâu ca  gim 1) và kéo nút  xut mc làm con nút . Chú
ý là sau phép 



, ta ch cn cp nht thông tin ph tr ca nút  và
  p nht thông tin ph tr ca nút  ng   ng ),
thông tin ph tr trong các núi.






Quay phi




















Quay trái
procedure UpTree(x: PNode);
var
y, z: PNode;
begin
y := x^.P;
//y^ là nút cha của x^
z := y^.P;
//z^ là nút cha của y^
if x = y^.L then
//Quay phải
begin
SetL(y, x^.R);
//Chuyển nhánh con phải của x^ sang làm con trái y^
SetR(x, y);
//Cho y^ làm con phải x^
end
else
//Quay trái
begin
SetR(y, x^.L);
//Chuyển nhánh con trái của x^ sang làm con phải y^
SetL(x, y);
//Cho y^ làm con trái x^

end;

//Móc nối x^ vào làm con z^ thay cho y^
if z^.L = y then SetL(z, x) else SetR(z, x);
Update(y); Update(x)
end;

2.1.5. Cây Splay
Trong ví d c th này, cây Splay c s dng làm cu trúc d liu cây biu
din danh sácht trong nhng thú v nht v cây nh phân
tìm kim t cân bng [8]c thc hin ngay
khi có lnh truy cp nút, làm gi  sâu ca nhng nút truy c ng
ng hp tn sut thc hin phép tìm kim trên mt khóa hay
mt c n so vi nhng khóa khác, cây Splay s phát huy
 v mt t.
 Thao tác Splay
Thao tác quan trng nht ca cây splay là thao tác 



: nhn vào mt
nút  y  lên làm gc cây: Nu  i gc cây, gi  là nút cha ca 
() và  là nút cha ca  (),  s y dn lên gc cây
theo quy trình sau:
 Nu  là con ca nút gc (), mt phép 



s c thc
hin và  s tr thành gc cây. Thao tác này gi là phép zig.

 Nu  và  cùng là con trái hoc cùng là con phi, mt phép 



s
c thc hi  y  lên làm nút cha ca , tip theo là mt phép




 y  lên làm nút cha ca . Thao tác này gi là phép zig-
zig.


 Nu  và  có mt nút là con trái và mt nút là con phi, hai phép




s c thc hi y  lên làm nút cha ca c  và . Thao
tác này gi là phép zig-zag.
Thao tác 



cn s dng tt phép zig.

Hình 4. Phép zig-zig và zig-zag.

procedure Splay(x: PNode);

var
y, z: PNode;
begin
repeat
y := x^.P;
if y = nilT then Break;
//x là gốc thì dừng ngay
z := y^.P;
if z ≠ nilT then
//zig-zig hoặc zig-zag, cần 1 phép UpTree trước phép UpTree(x)
if (y = z^.L) = (x = y^.L) then UpTree(y)
//x và y cùng là con trái hoặc cùng là con phải
else UpTree(x);
//x và y có một nút con trái và một nút con phải
UpTree(x);
until False;
end;

Ti sao li làm phc tp hóa v khi mà ta có th thc hin liên tip mt
lot các thao tác 



 y  lên gc cây?. Câu tr li là phép




ngoài viy  lên thành gng làm gi
sâu ca các nút nt  lên gcm ni bt ca



A
B
C

D


D
C
B

A
zig-zig

Bo toàn th t gia
zig-zag

Bo toàn th t gia


A
B
C

D

C
A


B
D

cây Splay: Nhng nút truy c ng xuyên s c làm gi  sâu và
phân b gn phía gc.
Hình 5 là ví d v c và sau khi thc hin thao tác 




. Thao tác





bao gm mt phép zig-zig, mt phép zig-zag và mt phép zig.
c khi 




, 

  sâu 0, 

   sâu ca các nút



là:
          
Sau khi 




, 

  sâu 0, 

và 

  sâu 1, 

và 

  sâu 2, 


 sâu 3. T sâu ca các nút 

là:
          

Hình 5. Ví d v thao tác Splay
 Tách
Phép tách (Split) nhn vào mt danh sách trng  (biu din bi cây )
và mt ch s    thành hai danh sách: Danh sách 



(biu din bi cây 

) gm  phn t u ca  và danh sách 

(biu din bi
cây 

) gm các phn t còn li trong . Thut toán tách có th din gi
sau:
 Nu , ta gán 

 và 

 b  ng hp này danh
sách 

 và 

.



















E
D
C
B
A
F
G









B
C
D
A




E
F



G











 Nu  x nh nút 

cha phn t ng th  bng hàm




y 

lên gc cây bng lnh 





nh 

là nút
con phi ca 

. Vì th t gic bo tn, nút 

vng th 
theo th t gia. Vic cui cùng ch là ct b liên kt gia 

và nhánh con
phi 

c to thành hai cây.
Chú ý rng sau phép tách cây  thành hai cây 

và 

, ta ph 
b hc s dng na.

procedure Split(T: PNode; i: Integer; var T1, T2: PNode);
begin
if i = 0 then
begin
T1 := nilT; T2 := T;
end
else

begin
T1 := NodeAt(T, i);
//T1: nút đứng thứ i theo thứ tự giữa
Splay(T1);
//Đẩy T1 lên làm gốc cây
T2 := T1^.R;
//T2 = con phải T1
T1^.R := nilT; T2^.P := nilT;
//Cắt liên kết T1 – T2
Update(T1);
//Tính lại thông tin phụ trợ trong T1 sau khi cắt liên kết
end;
end;

 Ghép
Vic ghép ni tip danh sách 

(biu din bi cây 

) vi danh sách 

(biu
din bi cây 

c thc hi
 Nu 

, danh sách 

rn ta tr v 


.
 Nu 

   nh nút cc phi ca 

(nút cha phn t ng
cui danh sách 

), tm gi là nút y  lên gc cây bng phép 




 chc chn không có nhánh con phi. Vic cui cùng ch là cho 


làm con phi ca  và tr v cây gc .

function Join(T1, T2: PNode): PNode;
begin
if T1 = nilT then Result := T2
//T1 rỗng thì trả về T2
else
begin
while T1^.R <> nilT do T1 := T1^.R;
//Đi xuống nút cực phải T1
Splay(T1);
//Đẩy lên gốc cây
SetR(T1, T2);

//Cho T2 làm con phải T1
Update(T1);
//Cập nhật lại thông tin phụ trợ trong T1
Result := T1;
//Trả về cây biểu diễn danh sách đã ghép
end;
end;

Chú ý rng sau phép ghép cây 

và 

thành mt cây , cây 

và 

phi coi
 hc s dng na.
 Chèn, xóa, cập nhật và truy vấn
 d t các phép bia
 tách và ghép.
 chèn phn t  vào v trí , ta tách cây biu din danh sách thành hai cây




. Cây 

biu din danh sách gm  phn t u tiên và cây 


biu
din danh sách gm các phn t còn li. To nút  cha phn t  và cho 




lt là con trái và con phi nút . Vic cui cùng là cp nht li thông tin
ph tr trong nút  và tr v cây gc  biu din danh sách m 
chèn phn t .
 xóa phn t ti v trí nh nút  cha phn t ng th , thc hin




 y  lên gc cây, ct ri nhánh con trái 

và nhánh con phi 


ca  c hin ghép 

vi 

c cây biu din danh sách mi sau
n t th . Vic cui cùng là gii phóng b nh cp cho nút .
 cp nht giá tr phn t ti v trí nh nút  cha phn t ng th
y  lên gc cây bng lnh 




p nht giá tr phn t 
trong  ng thi cp nht li các thông tin ph tr ca nút .
 tính tng các phn t t v trí  ti v trí , ta tách cây biu din danh sách
thành ba cây: Cây 

biu din danh sách gm  phn t u dãy, cây 


biu din danh sách gm các phn t nm trong phm vi truy vn t  ti  và
cây 

biu din danh sách t phn t th    n cui. Cui cùng ta tr v
giá tr  và tin hành ghép 3 cây lc ra phép truy vn này


có th tr li mà không cn dng các
 n hóa vit.
2.1.6. Cài đặt
 LISTQUERY.PAS  
{$MODE OBJFPC}
program SumQueries;
type
PNode = ^TNode;
TNode = record
//Cấu trúc nút
value: Integer;
P, L, R: PNode;
len: Integer;
sum: Int64;
end;

var
sentinel: TNode;
root, nilT: PNode;

procedure Init;
begin
nilT := @sentinel;
nilT^.len := 0;
nilT^.sum := 0;
root := nilT;
end;

procedure Update(x: PNode);
//Cập nhật thông tin phụ trợ trong nút x từ hai nút con
begin
x^.len := x^.L^.len + x^.R^.len + 1;
x^.sum := x^.L^.sum + x^.R^.sum + x^.value;
end;

procedure SetL(x, y: PNode);
//Đặt y làm cont trái x
begin
y^.P := x; x^.L := y;
end;

procedure SetR(x, y: PNode);
//Đặt y làm con phải x
begin
y^.P := x; x^.R := y;
end;


//Tìm nút thứ i trong cây gốc x
function NodeAt(x: PNode; i: Integer): PNode;
var
ord: Integer;
begin
repeat
ord := x^.L^.len + 1;
if ord = i then Break;
if i < ord then
x := x^.L
else
begin
i := i - ord;
x := x^.R;
end;
until False;
Result := x;
end;

procedure UpTree(x: PNode);
//Đẩy x lên cao hơn 1 mức bằng phép quay
var
y, z: PNode;
begin
y := x^.P;
z := y^.P;
if x = y^.L then
//Quay phải
begin

SetL(y, x^.R);
SetR(x, y);
end
else
//Quay trái
begin
SetR(y, x^.L);
SetL(x, y);
end;
if z^.L = y then SetL(z, x) else SetR(z, x);
Update(y); Update(x)
//Cập nhật thông tin phụ trợ trong x và y
end;

procedure Splay(x: PNode);
//Đẩy x lên thành gốc cây
var
y, z: PNode;
begin
repeat
y := x^.P;
if y = nilT then Break;
z := y^.P;
if z <> nilT then
if (y = z^.L) = (x = y^.L) then UpTree(y)
else UpTree(x);
UpTree(x);
until False;
end;


//Tách cây T thành 2 cây T1, T2, cây T1 gồm i phần tử đầu, cây T2 gồm các phần tử còn lại
procedure Split(T: PNode; i: Integer; var T1, T2: PNode);
begin
if i = 0 then
//i = 0, cây T1 rỗng
begin
T1 := nilT; T2 := T;
end
else
begin
T1 := NodeAt(T, i);
//Nhảy đến nút thứ i
Splay(T1);
//Đẩy lên gốc
T2 := T1^.R;
//Cắt nhánh con phải ra làm T2
T1^.R := nilT; T2^.P := nilT;


Update(T1);
//Cập nhật thông tin phụ trợ trong T1
end;
end;

function Join(T1, T2: PNode): PNode;
//Ghép nối tiếp hai danh sách T1, T2
begin
if T1 = nilT then Result := T2
else
begin

while T1^.R <> nilT do T1 := T1^.R;
//Nhảy đến nút cực phải của T1
Splay(T1);
//Đẩy lên gốc
SetR(T1, T2);
//Cho T2 làm con phải
Update(T1);
//Cập nhật thông tin phụ trợ
Result := T1;
end;
end;

//Các thao tác chính trên danh sách
procedure Insert(i: Integer; v: Integer);
//Chèn v vào vị trí i
var
T1, T2: PNode;
begin
if i > root^.len then i := root^.len + 1;
Split(root, i - 1, T1, T2);
//Tách thành hai danh sách con tại vị trí chèn
New(root);
//Tạo gốc mới chứa phần tử chèn vào
root^.value := v;
root^.P := nilT;
SetL(root, T1); SetR(root, T2);
//Cho hai danh sách con vào hai bên
Update(root);
//Cập nhật thông tin phụ trợ
end;


procedure Delete(i: Integer);
//Xóa phần tử thứ i
var
x, T1, T2: PNode;
begin
x := NodeAt(root, i);
//Nhảy tới nút chứa phần tử cần xóa
Splay(x);
//Đẩy lên gốc
T1 := x^.L; T1^.P := nilT;
T2 := x^.R; T2^.P := nilT;
Dispose(x);
//Giải phóng bộ nhớ
root := Join(T1, T2);
//Ghép nối tiếp hai danh sách hai bên vị trí xóa
end;

procedure Update(i: Integer; v: Integer);
//Cập nhật giá trị phần tử thứ i
begin
root := NodeAt(root, i);
//Nhảy tới nút chứa phần tử thứ i
Splay(root);
//Đẩy lên gốc
root^.value := v;
//Đặt giá trị mới
Update(root);
//Cập nhật lại thông tin phụ trợ (sum)
end;


function Query(i, j: Integer): Int64;
//Tính tổng các phần tử từ i tới j
var
T1, T2, T3: PNode;
begin
Split(root, j, T2, T3); Split(T2, i - 1, T1, T2);
//Tách thành 3 danh sách nối tiếp T1, T2,T3
Result := T2^.sum;
//Trả về tổng các phần tử trong T2
Root := Join(Join(T1, T2), T3);
//Ghép lại
end;

procedure Solve;
var
c: Char;
k, p: Integer;
i, j: Integer;
v: Integer;
begin
ReadLn(k);
for p := 1 to k do
begin
Read(c);
case c of
'I':
begin
ReadLn(i, v);
Insert(i, v);

end;
'D':
begin
ReadLn(i);
Delete(i);
end;
'U':
begin
ReadLn(i, v);
Update(i, v);
end;
'Q':
begin
ReadLn(i, j);
WriteLn(Query(i, j));
end;
end;
end;
end;

procedure FreeMemory(x: PNode);
begin
if x = nilT then Exit;
FreeMemory(x^.L);
FreeMemory(x^.R);
Dispose(x);
end;

begin
Init;

Solve;
FreeMemory(root);
end.
Thi gian thc hin gii thut có th  ln thc hin thao tác
 và s li gi hàm . Nhn xét rng mi khi phép truy cp phn t


  gc xung mt lnh  chuyn nút
c. Chính vì vy thi gian thc hin gii thut có th 
các thao tác , s thao tác  cn thc hin là mng 



.
Các nghiên cu lý thuy ra rng mt phép  thc hin riêng r có
th mt thi gian 



vi  là s nút trên cây. Tuy vy, thi gian thc hin c
dãy gm  thao tác  tính tng li ch là 



. Tc là ta có
th coi mi phép cp nht/truy vc thc hin trong thi gian 





 - amortized analysis) khi .
c rng cây Splay có thi gian thc hin gii
thut trên mt dãy thao tác chèn/xóa/tìm kim   i cây nh
phân tìm kim tng ký pháp O ln (sai khác
mt hng s n trong ký pháp O).
2.2. Cây quản lý đoạn
Segment trees [2] là mt cu trúc d liu c thit k cho các ng
dng hình hc. Cu trúc này khá phc tc s d tr li nhiu
loi truy vn khó. c so sánh vi interval trees là mt
dng cu trúc d lip các ch
Trong mn hóa cu trúc segment trees  gii quyt bài toán
truy vn phu này làm cho cây qun ch ging vi segment
trees  hình nh biu din còn các thu c tr 
giu so vi cu trúc nguyên th li
c nhng truy vu trúc nguyên thy.
Trên các dio lun v thuc và th gii, 
gi interval trees hoc segment trees v gi tên cu trúc này,
tuy nhiên tôi không tìm th nó trong các cun sách thut toán
ph bin [3] [1] [4]. Các bài ging thu dùng tên gi interval
trees và segment trees   cp ti hai cu trúc d liu trong hình hc tính
toán. Cu trúc mà mn, tôi tm gi là cây qun lý n, ch là mt
hn ch cng hp c th.
Mi bài toán gii quyc bng cây qun u có th gic bng
cu trúc d li mc 2.1c l
Mc dù vy, cây qun cung cp mt cách qun lý mi thông qua các
p, ngoài ra vit d m ca cu trúc d
liu này. Ta gii hn li bà     ng h c bit:
không có phép chèn và xóa phn t  kho sát cu trúc d liu cây qun lý
n.
Bài toán: (Range Query 2).

Cho mt dãy gm  s nguyên 








. Xét hai phép bii:
 Phép cp nht 



t 


 Phép truy vn 



: Tr v tng các phn t t 

ti 


Yêu cu: Cho dãy  thao tác thc hin tun t, hãy tr li tt c các truy vn

Input
 Dòng 1 cha 2 s  



 Dòng 2 cha  s nguyên 






  dòng tip, mi dòng cho thông tin v mt phép bii. Mi dòng bt
u bi mt ký t 




 Nu ký t p theo là hai s nguyên  ng
vi phép cp nht 



(

)
 Nu ký t p theo là hai s nguyên  ng
vi phép truy vn 



()
Output

Tr li tt c các truy vn , vi mi truy vn in ra câu tr li trên 1 dòng
Sample Input
Sample Output
9 5
1 2 3 4 5 6 7 8 9
U 1 5 //5 2 3 4 5 6 7 8 9
U 3 6 //5 2 6 4 5 6 7 8 9
Q 1 4
U 8 1 //5 2 6 4 5 6 7 1 9
Q 1 9
17
45



2.2.1. Cấu trúc
Cây qu n là mt cây nh phân  (full binary trees) có cu trúc

 Mi nút qun lý mng liên tip, trong nút cha thông tin
tng hp t ng mà nó qun lý ng hp c th này,
mi nút cha tng ca các phn t trong phm vi mà nó qun lý).
 Nút gc qung t 1 ti .
 Nu mt nút qung t  ti  () thì nút con trái
ca nó qung t  ti  và nút con phi ca nó qun lý các
ng t    ti .  






.
 Nu mt nút ch qun lý mng thì nó s là nút lá và không có nút
con. Trong mt s ng hp cc thut toán, mng  s
c gn vi mt con tr 



tr ti nút lá qun lý trc ting
.
 thun tin cho trình bày, vi mi nút   s 

và 

cho
bit  qun lý các phn t t trong mng  t ch s 

ti ch s 

.
Hình 6 là ví d v cây qun gm ng

Hình 6. Cây qun
Bổ đề 1
Vi mi s  sâu ca các nút lá trên cây qun gm 
t quá 

  


Chứng minh

Gi 



 sâu ln nht ca mt nút lá trên cây qun gm 
 xây dng cây: nút con trái ca nút gc qun lý




[1]
[2]

[3]
3]
[4]
[5]
[45]
6]
[46]
6]
ng và nút con phi ca nút gc qun lý



ng. Tc là nu xét
v  sâu:






 




  

(1)
Rõ ràng khi , ta có 



, b  
Khi , ta chng minh bng thc m





  

.
Khi  ta có 






  

, bng th
ng hp , bng thc s c chng minh bng quy np theo :








 






 

 


  

 





 





(2)
Bổ đề 2
Vi mi s  sâu ca các nút lá trên cây qun gm 
ng không nh 

  

 
Chứng minh
Gi 



 sâu nh nht ca mt nút lá trên cây qun gm 
 xây dng cây, ta có:





 





  

(3)
Rõ ràng khi , ta có 



, b  
Khi , b  c chng minh bng quy np theo :








 




 

   





 




  

  


  




  

 
(4)


B  1 và B  2 ch ra r sâu c cao ca cây là
mng 



 cho phép biu di
i gian thc hin gii thut.
2.2.2. Biểu diễn

Ta s s dng m biu din cây qun  quen thuc:
Nút g 1, nút  có nút con trái là nút , nút con phi là nút
 và nút cha nút cha



. Mun vy ta cc mng
cn khai báo.
Xét mt cây qun  cao , ta thêm cho nút cc trái ca cây mt nút lá
bên trái, gi là nút . Do phép xây dng cây, nút lá  này chc ch sâu
lt c   ln nht.
Theo   s, nút lá s có ch s 

(do nó là lá cc trái và nm
  sâu   
B  1   ra rng cây qun lý danh sách  phn t có chiu cao


  

    s ca nút lá  không bao gi t quá






  y ch s các nút còn li không t quá
  .
 d nh ng khai báo mng vi các phn t  t 1

ti .
Th tc 



i to nhánh cây gc  qui
ng 

ti 

:

procedure Build(x: Integer; low, high: Integer);
var
middle: Integer;
begin
l[x] := low; h[x] := high;
if low = high then
//Nút x là một lá quản lý duy nhất một đối tượng a[low]
begin
sum[x] := a[low]
leaf[low] := x;
end
else
//Nút x là nút nhánh và sẽ có đúng 2 nút con
begin
middle := (low + high) div 2;
Build(x * 2, low, middle);
//Khởi tạo nhánh con trái quản lý các đối tượng low…middle
Build(x * 2 + 1, middle + 1, high);

//Khởi tạo nhánh con phải quản lý các đối tượng middle + 1…high
sum[x] := sum[2 * x] + sum[2 * x + 1]);
//Tổng hợp thông tin tổng từ 2 nút con lên nút x
end;
end;

Th tc khi to cây qu  n s c thc hin bng li gi




. Vic khi tc thc hin trong thi gian 



.
2.2.3. Cập nhật
Thao tu tiên trên cây qun là phi cp nht li cây mi khi có s
 i giá tr phn t. Khi mt phn t 

b  i, ta nhy ti nút




là nút lá trc tip qun lý 

 nút  lên gc, c 
nào thì cp nht li thông tin tng 




. Sau quá trình này, tt c các nút
cha phn t 

trong phm vi qun lý s c cp nht li thông tin tng




.
Th tc 



u chnh li cây qun khi có s thay
i 



procedure Update(i: Integer; v: Integer);
var
x: Integer;
begin
x := leaf[i];
//Nhảy tới nút lá quản lý trực tiếp đối tượng i
sum[x] := v;
//Cập nhật thông tin tại lá x
while x > 1 do
//Chừng nào x chưa phải là gốc

begin
x := x div 2;
//Nhảy lên nút cha của x rồi cập nhật thông tin tổng
sum[x] := sum[2 * x] + sum[2 * x + 1];
end;
end;

×