From 3d13d0a26866ac539a8e437f15586ab90a3a6667 Mon Sep 17 00:00:00 2001
From: Martin Mares <mj@ucw.cz>
Date: Thu, 7 Mar 2019 19:07:38 +0100
Subject: [PATCH] Splay: Translated some parts from the Labyrinth book

---
 02-splay/Makefile         |   4 +
 02-splay/log-avg.asy      |  36 ++++++
 02-splay/splay-delete.asy |  68 +++++++++++
 02-splay/splay-pot.asy    |  96 +++++++++++++++
 02-splay/splay-rotate.asy | 188 +++++++++++++++++++++++++++++
 02-splay/splay-steps.asy  |  65 ++++++++++
 02-splay/splay.py         | 183 ++++++++++++++++++++++++++++
 02-splay/splay.tex        | 243 ++++++++++++++++++++++++++++++++++++++
 pics/ads.asy              | 184 +++++++++++++++++++++++++++++
 pics/pdftex               |   3 +
 pics/trees.asy            | 192 ++++++++++++++++++++++++++++++
 tex/adsmac.tex            |  12 +-
 12 files changed, 1266 insertions(+), 8 deletions(-)
 create mode 100644 02-splay/Makefile
 create mode 100644 02-splay/log-avg.asy
 create mode 100644 02-splay/splay-delete.asy
 create mode 100644 02-splay/splay-pot.asy
 create mode 100644 02-splay/splay-rotate.asy
 create mode 100644 02-splay/splay-steps.asy
 create mode 100755 02-splay/splay.py
 create mode 100644 02-splay/splay.tex
 create mode 100644 pics/ads.asy
 create mode 100755 pics/pdftex
 create mode 100644 pics/trees.asy

diff --git a/02-splay/Makefile b/02-splay/Makefile
new file mode 100644
index 0000000..076aebb
--- /dev/null
+++ b/02-splay/Makefile
@@ -0,0 +1,4 @@
+TOP=..
+PICS=splay-rotate splay-steps splay-pot splay-delete log-avg
+
+include ../Makerules
diff --git a/02-splay/log-avg.asy b/02-splay/log-avg.asy
new file mode 100644
index 0000000..6006476
--- /dev/null
+++ b/02-splay/log-avg.asy
@@ -0,0 +1,36 @@
+import ads;
+import graph;
+
+real aspect = 0.5;
+size(100mm, 100mm*aspect, IgnoreAspect);
+
+real f(real x) { return log(x) / log(2); }
+
+xaxis("$x$", xmin=0, xmax=20);
+yaxis("$y$", ymin=0, ymax=5);
+draw(graph(f, 1, 20));
+
+real a = 1.5;
+real b = 18;
+real c = (a+b)/2;
+pair aa = (a, f(a));
+pair bb = (b, f(b));
+pair cc = (aa + bb)/2;
+pair dd = (c, f(c));
+
+void pt(pair x)
+{
+	fill(shift(x) * scale(0.1, 0.1*aspect) * unitcircle);
+}
+
+pt(aa);
+pt(bb);
+pt(cc);
+pt(dd);
+draw(aa -- bb, halfthick);
+draw((c,0) -- (c,f(c)+1), dotted);
+
+label("$A=(\alpha,f(\alpha))$", aa, SE);
+label("$B=(\beta,f(\beta))$", bb, 2*dir(-55));
+label("$S'=\left({\alpha+\beta\over 2},f\!\left({\alpha+\beta\over 2}\right)\right)$", dd, 3*dir(140));
+label("$S=\left({\alpha+\beta\over 2},{f(\alpha)+f(\beta)\over 2}\right)$", cc, 2*dir(-35));
diff --git a/02-splay/splay-delete.asy b/02-splay/splay-delete.asy
new file mode 100644
index 0000000..36b5380
--- /dev/null
+++ b/02-splay/splay-delete.asy
@@ -0,0 +1,68 @@
+import ads;
+import trees;
+
+void t(int parent_id, real rangle, int rsize, int key)
+{
+	tnode v = tn_add(parent_id, rangle);
+	v.draw_vertex = new void (tnode w) {
+		vertex(w.id, mode=(key == 2 ? v_lightgray : v_white));
+		label("\eightrm " + (string) key, w.pos);
+	};
+}
+
+void d(string op, pair pos)
+{
+	label("$\hbox{\sevenrm " + op + "}\atop\longrightarrow$", pos);
+}
+
+tree_node_size = 0.15;
+tn_edge_len = 0.7;
+
+tn_init((0, 0));
+t(-1,0,7,5);	// 0
+t(0,-20,5,0);	// 1
+t(1,10,4,2);	// 2
+t(2,-20,1,1);	// 3
+t(2,20,2,4);	// 4
+t(4,-10,1,3);	// 5
+t(0,20,1,6);	// 6
+tn_draw();
+
+label("$\longrightarrow$", (1,-1));
+
+tn_init((2.5,0));
+t(-1,0,7,2);	// 0
+t(0,-40,2,0);	// 1
+t(1,10,1,1);	// 2
+t(0,40,4,5);	// 3
+t(3,-20,2,4);	// 4
+t(4,-10,1,3);	// 5
+t(3,20,1,6);	// 6
+tn_draw();
+
+label("$\longrightarrow$", (4,-1));
+
+tn_init((4.8,-tn_edge_len));
+t(-1,0,2,0);	// 0
+t(0,10,1,1);	// 1
+tn_draw();
+
+tn_init((6,-tn_edge_len));
+t(-1,0,4,5);	// 0
+t(0,-20,2,4);	// 1
+t(1,-10,1,3);	// 2
+t(0,20,1,6);	// 3
+tn_draw();
+
+label("$\longrightarrow$", (7,-1));
+
+tn_init((8.5,0));
+t(-1,0,2,1);	// 0
+t(0,-40,1,0);	// 1
+t(0,40,4,5);	// 2
+t(2,-20,2,4);	// 3
+t(3,-10,1,3);	// 4
+t(2,20,1,6);	// 5
+tnodes[2].parent = null;
+draw(tn_pos[0] -- tn_pos[2], thick);
+tn_draw();
diff --git a/02-splay/splay-pot.asy b/02-splay/splay-pot.asy
new file mode 100644
index 0000000..cce84d7
--- /dev/null
+++ b/02-splay/splay-pot.asy
@@ -0,0 +1,96 @@
+import ads;
+import trees;
+
+pair s = (2.5, 0);
+tree_node_size = 0.15;
+tn_edge_len = 0.7;
+int goal;
+
+void t(int parent_id, real rangle, int rsize, int key)
+{
+	tnode v = tn_add(parent_id, rangle);
+	v.draw_vertex = new void (tnode w) {
+		vertex(w.id, mode=(key == goal ? v_lightgray : v_white));
+		label("\eightrm " + (string) key, w.pos);
+	};
+}
+
+void phi(real p)
+{
+	label("\eightrm " + (string) p, tn_ref + (0,0.6));
+}
+
+tn_init();
+goal = 9;
+t(-1,0,10,0);	// 0
+t(0,10,9,1);	// 1
+t(1,10,8,2);	// 2
+t(2,10,7,3);	// 3
+t(3,10,6,4);	// 4
+t(4,10,5,5);	// 5
+t(5,10,4,6);	// 6
+t(6,10,3,7);	// 7
+t(7,10,2,8);	// 8
+t(8,10,1,9);	// 9
+tn_draw();
+phi(21.791);
+
+tn_init(s);
+goal = 0;
+t(-1,0,10,9);	// 0
+t(0,-20,9,0);	// 1
+t(1,10,8,2);	// 2
+t(2,-20,1,1);	// 3
+t(2,20,6,4);	// 4
+t(4,-20,1,3);	// 5
+t(4,20,4,6);	// 6
+t(6,-20,1,5);	// 7
+t(6,20,2,8);	// 8
+t(8,-10,1,7);	// 9
+tn_draw();
+phi(15.077);
+
+tn_init(1.8*s);
+goal = 7;
+t(-1,0,10,0);	// 0
+t(0,20,9,9);	// 1
+t(1,-20,8,2);	// 2
+t(2,-20,1,1);	// 3
+t(2,20,6,4);	// 4
+t(4,-20,1,3);	// 5
+t(4,20,4,6);	// 6
+t(6,-20,1,5);	// 7
+t(6,20,2,8);	// 8
+t(8,-20,1,7);	// 9
+tn_draw();
+phi(15.077);
+
+tn_init(3*s);
+goal = 3;
+t(-1,0,10,7);	// 0
+t(0,-40,7,0);	// 1
+t(1,10,6,4);	// 2
+t(2,-30,3,2);	// 3
+t(3,-15,1,1);	// 4
+t(3,15,1,3);	// 5
+t(2,30,2,6);	// 6
+t(6,-10,1,5);	// 7
+t(0,40,2,9);	// 8
+t(8,-10,1,8);	// 9
+tn_draw();
+phi(12.299);
+
+tn_init(4*s);
+goal = -1;
+t(-1,0,10,3);	// 0
+t(0,-40,3,0);	// 1
+t(1,10,2,2);	// 2
+t(2,-10,1,1);	// 3
+t(0,40,6,7);	// 4
+t(4,-30,3,4);	// 5
+t(5,10,2,6);	// 6
+t(6,-10,1,5);	// 7
+t(4,30,2,9);	// 8
+t(8,-10,1,8);	// 9
+tn_draw();
+phi(12.077);
diff --git a/02-splay/splay-rotate.asy b/02-splay/splay-rotate.asy
new file mode 100644
index 0000000..d5f4777
--- /dev/null
+++ b/02-splay/splay-rotate.asy
@@ -0,0 +1,188 @@
+import ads;
+import trees;
+
+pair e = bst_edge;
+pair le = rotate(-45) * e;
+pair re = rotate(45) * e;
+pair le1 = rotate(-60) * e * 1.2;
+pair re1 = rotate(60) * e * 1.2;
+pair le2 = rotate(-45) * e * 0.7;
+pair re2 = rotate(45) * e * 0.7;
+
+real ux = 0;
+real vx = 5.5;
+real ly = 0;
+real lly = -3.2;
+real lry = -6.8;
+real arrlen = 0.5;
+real arrx = (ux+vx)/2;
+real arry = -0.5;
+
+/*** L: předtím ***/
+
+pair lu[];
+lu[0] = (ux, ly);
+lu[1] = lu[0] + le;
+lu[2] = lu[0] + re;
+lu[3] = lu[1] + le2;
+lu[4] = lu[1] + re2;
+lu[5] = lu[0] + bst_mini;
+
+tree_init(lu);
+tree_edge(0, 1, thick);
+tree_edge(0, 2);
+tree_edge(0, 5);
+tree_edge(1, 3);
+tree_edge(1, 4);
+tree_node(0, "y");
+tree_node(1, "x");
+tree_sub(2, "C");
+tree_sub(3, "A");
+tree_sub(4, "B");
+
+/*** L: potom ***/
+
+pair lv[];
+lv[0] = (vx, ly);
+lv[1] = lv[0] + re;
+lv[2] = lv[0] + le;
+lv[3] = lv[1] + le2;
+lv[4] = lv[1] + re2;
+lv[5] = lv[0] + bst_mini;
+
+tree_init(lv);
+tree_edge(0, 1, thick);
+tree_edge(0, 2);
+tree_edge(0, 5);
+tree_edge(1, 3);
+tree_edge(1, 4);
+tree_node(0, "x");
+tree_node(1, "y");
+tree_sub(2, "A");
+tree_sub(3, "B");
+tree_sub(4, "C");
+
+/*** LL: předtím ***/
+
+pair llu[];
+llu[0] = (ux, lly);		// z
+llu[1] = llu[0] + le1;		// y
+llu[2] = llu[1] + le;		// x
+llu[3] = llu[0] + re1;		// D
+llu[4] = llu[1] + re;		// C
+llu[5] = llu[2] + le2;		// A
+llu[6] = llu[2] + re2;		// B
+llu[7] = llu[0] + bst_mini;
+
+tree_init(llu);
+tree_edge(0, 1, thick);
+tree_edge(1, 2, thick);
+tree_edge(0, 3);
+tree_edge(0, 7);
+tree_edge(1, 4);
+tree_edge(2, 5);
+tree_edge(2, 6);
+tree_node(0, "z");
+tree_node(1, "y");
+tree_node(2, "x");
+tree_sub(3, "D");
+tree_sub(4, "C");
+tree_sub(5, "A");
+tree_sub(6, "B");
+
+/*** LL: poté ***/
+
+pair llv[];
+llv[0] = (vx, lly);		// x
+llv[1] = llv[0] + re1;		// y
+llv[2] = llv[1] + re;		// z
+llv[3] = llv[0] + le1;		// A
+llv[4] = llv[1] + le;		// B
+llv[5] = llv[2] + le2;		// C
+llv[6] = llv[2] + re2;		// D
+llv[7] = llv[0] + bst_mini;
+
+tree_init(llv);
+tree_edge(0, 1, thick);
+tree_edge(1, 2, thick);
+tree_edge(0, 7);
+tree_edge(0, 3);
+tree_edge(1, 4);
+tree_edge(2, 5);
+tree_edge(2, 6);
+tree_node(0, "x");
+tree_node(1, "y");
+tree_node(2, "z");
+tree_sub(3, "A");
+tree_sub(4, "B");
+tree_sub(5, "C");
+tree_sub(6, "D");
+
+/*** LP: předtím ***/
+
+pair lru[];
+lru[0] = (ux, lry);		// y
+lru[1] = lru[0] + le1;		// w
+lru[2] = lru[1] + re;		// x
+lru[3] = lru[0] + re1;		// D
+lru[4] = lru[1] + le;		// A
+lru[5] = lru[2] + le2;		// B
+lru[6] = lru[2] + re2;		// C
+lru[7] = lru[0] + bst_mini;
+
+tree_init(lru);
+tree_edge(0, 1, thick);
+tree_edge(1, 2, thick);
+tree_edge(0, 3);
+tree_edge(0, 7);
+tree_edge(1, 4);
+tree_edge(2, 5);
+tree_edge(2, 6);
+tree_node(0, "y");
+tree_node(1, "w");
+tree_node(2, "x");
+tree_sub(3, "D");
+tree_sub(4, "A");
+tree_sub(5, "B");
+tree_sub(6, "C");
+
+/*** LP: poté ***/
+
+pair lrv[];
+lrv[0] = (vx+0.2, lry);		// x
+lrv[1] = lrv[0] + le1;		// w
+lrv[2] = lrv[0] + re1;		// y
+lrv[3] = lrv[1] + le2;		// A
+lrv[4] = lrv[1] + re2;		// B
+lrv[5] = lrv[2] + le2;		// C
+lrv[6] = lrv[2] + re2;		// D
+lrv[7] = lrv[0] + bst_mini;
+
+tree_init(lrv);
+tree_edge(0, 1, thick);
+tree_edge(0, 2, thick);
+tree_edge(0, 7);
+tree_edge(1, 3);
+tree_edge(1, 4);
+tree_edge(2, 5);
+tree_edge(2, 6);
+tree_node(0, "x");
+tree_node(1, "w");
+tree_node(2, "y");
+tree_sub(3, "A");
+tree_sub(4, "B");
+tree_sub(5, "C");
+tree_sub(6, "D");
+
+/*** Šipky ***/
+
+void arr(real y, string lab)
+{
+	y += arry;
+	draw((arrx-arrlen, y) -- (arrx+arrlen, y), Arrow(size=6));
+	label("\bf " + lab, (arrx, y), 1.5N);
+}
+
+arr(ly, "zig");
+arr(lly, "zig-zig");
+arr(lry, "zig-zag");
diff --git a/02-splay/splay-steps.asy b/02-splay/splay-steps.asy
new file mode 100644
index 0000000..b869afa
--- /dev/null
+++ b/02-splay/splay-steps.asy
@@ -0,0 +1,65 @@
+import ads;
+import trees;
+
+void t(int parent_id, real rangle, int rsize, int key)
+{
+	tnode v = tn_add(parent_id, rangle);
+	v.draw_vertex = new void (tnode w) {
+		vertex(w.id, mode=(key == 5 ? v_lightgray : v_white));
+		label("\eightrm " + (string) key, w.pos);
+	};
+}
+
+void d(string op, pair pos)
+{
+	label("$\hbox{\sevenrm " + op + "}\atop\longrightarrow$", pos);
+}
+
+tree_node_size = 0.17;
+tn_edge_len = 0.72;
+
+tn_init();
+t(-1,0,7,0);	// 0
+t(0,10,6,1);	// 1
+t(1,10,5,2);	// 2
+t(2,10,4,3);	// 3
+t(3,10,3,4);	// 4
+t(4,10,2,5);	// 5
+t(5,10,1,6);	// 6
+tn_draw();
+
+d("zig-zig", (1.25, -1));
+
+tn_init((2.5, 0));
+t(-1,0,7,0);	// 0
+t(0,10,6,1);	// 1
+t(1,10,5,2);	// 2
+t(2,10,4,5);	// 3
+t(3,-20,2,4);	// 4
+t(4,-10,1,3);	// 5
+t(3,20,1,6);	// 6
+tn_draw();
+
+d("zig-zig", (3.75, -1));
+
+tn_init((5, 0));
+t(-1,0,7,0);	// 0
+t(0,10,6,5);	// 1
+t(1,-20,4,2);	// 2
+t(2,-20,1,1);	// 3
+t(2,20,2,4);	// 4
+t(4,-10,1,3);	// 5
+t(1,20,1,6);	// 6
+tn_draw();
+
+d("zig", (6.25, -1));
+
+tn_init((7.5, 0));
+t(-1,0,7,5);	// 0
+t(0,-20,5,0);	// 1
+t(1,10,4,2);	// 2
+t(2,-20,1,1);	// 3
+t(2,20,2,4);	// 4
+t(4,-10,1,3);	// 5
+t(0,20,1,6);	// 6
+tn_draw();
diff --git a/02-splay/splay.py b/02-splay/splay.py
new file mode 100755
index 0000000..5542420
--- /dev/null
+++ b/02-splay/splay.py
@@ -0,0 +1,183 @@
+#!/usr/bin/python3
+
+import math
+import sys
+
+class Node:
+
+    def __init__(self, key, l=None, r=None, p=None):
+        self.key = key
+        self.l = l
+        self.r = r
+        self.p = p
+        if l != None:
+            l.p = self
+        if r != None:
+            r.p = self
+
+    def find(x, k):
+        if x == None or x.key == k:
+            return x
+        if k < x.key:
+            return Node.find(x.l, k)
+        else:
+            return Node.find(x.r, k)
+
+    def insert(x, k, p=None):
+        if x == None:
+            return Node(k, None, None, p)
+        elif k < x.key:
+            x.l = Node.insert(x.l, k, x)
+        else:
+            x.r = Node.insert(x.r, k, x)
+        return x
+
+    def rr(y):
+        x = y.l
+        b = x.r
+        x.r = y
+        y.l = b
+        p = y.p
+        if p != None:
+            if p.l == y:
+                p.l = x
+            else:
+                p.r = x
+        x.p = p
+        y.p = x
+        if b != None:
+            b.p = y
+
+    def rl(x):
+        y = x.r
+        b = y.l
+        y.l = x
+        x.r = b
+        p = x.p
+        if p != None:
+            if p.r == x:
+                p.r = y
+            else:
+                p.l = y
+        y.p = p
+        x.p = y
+        if b != None:
+            b.p = x
+
+    def splay_step(x):
+        p = x.p
+        pp = p.p
+        if pp == None:
+            if x == p.l:
+                p.rr()
+            else:
+                p.rl()
+        else:
+            if p == pp.l:
+                if x == p.l:
+                    pp.rr()
+                    p.rr()
+                else:
+                    p.rl()
+                    pp.rr()
+            else:
+                if x == p.l:
+                    p.rr()
+                    pp.rl()
+                else:
+                    pp.rl()
+                    p.rl()
+
+    def splay(x):
+        if x == None or x.p == None:
+            return x
+        x.splay_step()
+        return x.splay()
+
+    def dump(x, depth=1, parent=None):
+        if x == None:
+            return
+        if x.p != parent:
+            print("### BAD PARENT LINK ###")
+        Node.dump(x.r, depth+1, x)
+        print("    " * depth + str(x.key) + " [" + str(x.size) + "]")
+        Node.dump(x.l, depth+1, x)
+
+    def sizes(x):
+        s = 1
+        if x.l != None:
+            x.l.sizes()
+            s += x.l.size
+        if x.r != None:
+            x.r.sizes()
+            s += x.r.size
+        x.size = s
+        x.rank = math.log(s, 2)
+
+    def phi(x):
+        if x == None:
+            return 0
+        else:
+            return x.rank + Node.phi(x.l) + Node.phi(x.r)
+
+    def export(x, id=0, parent=-1, ang=0):
+        if x == None:
+            return id
+        print("t({0:d},{1:d},{2:d},{3:d});	// {4:d}".format(parent, ang, x.size, x.key, id))
+        pid = id
+        id += 1
+        id = Node.export(x.l, id, pid, -10)
+        id = Node.export(x.r, id, pid, 10)
+        return id
+
+    def show(x):
+        x.sizes()
+        x.dump()
+        print()
+        print("tn_init();")
+        x.export()
+        print("tn_draw();")
+        print("phi({0:.3f});".format(x.phi()))
+        print("", "-" * 60)
+
+mode = ""
+if len(sys.argv) > 1:
+    mode = sys.argv[1]
+
+if mode == "steps":
+    r = None
+    for i in range(0, 7):
+        r = Node.insert(r, i)
+    five = r.find(5)
+    r.show()
+    five.splay_step()
+    r.show()
+    five.splay_step()
+    r.show()
+    five.splay_step()
+    five.show()
+elif mode == "delete":
+    r = None
+    r = Node.insert(r, 5)
+    r = Node.insert(r, 0)
+    r = Node.insert(r, 6)
+    r = Node.insert(r, 2)
+    r = Node.insert(r, 1)
+    r = Node.insert(r, 4)
+    r = Node.insert(r, 3)
+    r.show()
+    r = r.find(2).splay()
+    r.show()
+else:
+    r = None
+    for i in range(0, 10):
+        r = Node.insert(r, i)
+    r.show()
+    r = r.find(9).splay()
+    r.show()
+    r = r.find(0).splay()
+    r.show()
+    r = r.find(7).splay()
+    r.show()
+    r = r.find(3).splay()
+    r.show()
diff --git a/02-splay/splay.tex b/02-splay/splay.tex
new file mode 100644
index 0000000..9299b43
--- /dev/null
+++ b/02-splay/splay.tex
@@ -0,0 +1,243 @@
+\ifx\chapter\undefined
+\input adsmac.tex
+\singlechapter{2}
+\fi
+
+\chapter[splay]{Splay trees}
+
+In this chapter, we will present self-adjusting binary search trees called the Splay trees.
+They were discovered in 1983 by Daniel Sleator and Robert Tarjan. They are based on a~very
+simple idea: whenever we access a~node, we bring it to the root by a~sequence of rotations.
+Surprisingly, this is enough to guarantee amortized $\O(\log n)$ cost of all operations.
+In cases when the items are accessed with uneven probabilities, the Splay trees will turn out
+to be even superior to ordinary balanced trees.
+
+\section{Splaying}
+
+Let us consider an~arbitrary binary tree. We define the operation $\opdf{Splay}(x)$,
+which brings the node~$x$ to the root using rotations. This can be obviously done by repeatedly
+rotating the edge above~$x$ until $x$~becomes the root, but this does not lead to good amortized
+complexity (see exercise~\exref{splaynaive}).
+
+The trick is to prefer double rotations as shown in figure~\figref{splayrot}.
+If~$x$ is a~left child of a~left child (or symetrically a~right child of a~right child),
+we perform the \em{zig-zig} step. If~$x$ is a~right child of a~left child (or vice versa),
+we do the \em{zig-zag} step. When $x$ finally becomes a~child of the root, we perform
+a~single rotation --- the \em{zig} step.
+
+\figure[splayrot]{splay-rotate.pdf}{}{Three types of splay steps}
+
+We can see the process of splaying in figure~\figref{splaysteps}: First we perform
+a~zig-zig, then again a~zig-zig, and finally a~single zig. You can see that splaying
+tends to reform long paths to branched trees. This gives us hope that randomly appearing
+degenerate subtrees will not stay for long.
+
+\figure[splaysteps]{splay-steps.pdf}{}{Steps of splaying the node~5}
+
+Our amortized analysis will be based on a~cleverly chosen potential. It might look
+magical, as if Sleator and Tarjan pulled it out of a~magician's hat. But once we define
+the potential, the rest of the analysis becomes straightforward.
+
+\nota{
+\tightlist{o}
+\:$T(v)$ denotes the subtree rooted at the node~$v$.
+\:The \em{size} $s(v)$ is the cardinality of the subtree $T(v)$.
+\:The \em{rank} $r(v)$ is the binary logarithm of~$s(v)$.
+\:The \em{potential} of the splay tree is the sum of ranks of all nodes.
+\endlist
+}
+
+\figure[splaypot]{splay-pot.pdf}{}{Evolution of potential during splays of nodes 9, 0, 7, 3}
+
+Figure~\figref{splaypot} suggests that higher potentials correspond to less
+balanced trees. By repeated splaying, the path gradually becomes a~branching tree.
+The potential keeps decreasing; it decreases faster during expensive splays.
+
+We are going to prove that this holds in general. We will measure the cost of splaying
+in the number of rotations performed (so a~zig-zig or zig-zag counts as two rotations).
+Real time complexity is obviously linear in this cost.
+
+\theorem{
+Amortized cost of $\alg{Splay}(x)$ is at most $3\cdot(r'(x) - r(x)) + 1$,
+where $r(x)$ is the rank of the node~$x$ before the operation and $r'(x)$ the
+rank after it.
+}
+
+\proof
+The amortized cost of the full \alg{Splay} is a~sum of amortized costs of the individual steps.
+Let $r_1(x),\ldots,r_t(x)$ denote the rank of~$x$ after each step and $r_0(x)$ the rank
+before the first step.
+
+We are going to prove several lemmas, which guarantee that the amortized cost of the $i$-th step is bounded
+by $3r_i(x) - 3r_{i-1}(x)$. The sole exception is the final zig step, whose cost can be greater by~1.
+The total amortized cost is therefore
+$$
+A \le \sum_{i=1}^t \bigl(3r_i(x) - 3r_{i-1}(x) \bigr) + 1.
+$$
+This is a~telescopic sum: each rank except $r_0$ and~$r_t$ is participates once positively
+and once negatively. Therefore the right-hand side is equal to $3r_t(x) - 3r_0(x) + 1$
+as claimed by the theorem.
+\qed
+
+\corr{
+As all ranks are logarithmic, the amortized cost of \alg{Splay} is $\O(\log n)$.
+}
+
+Before we get to analysis of the individual steps, we prove a~simple lemma bounding
+a~mean of logarithms.
+
+\lemman{mean of logarithms}{
+For any two positive real numbers $\alpha,\beta$ we have:
+$$
+	\log{\alpha+\beta\over 2} \ge {\log \alpha + \log \beta \over 2}.
+$$
+\unparskip
+}
+
+\proof
+The inequality holds not only for logarithm, but for an~arbitrary \em{concave} function~$f$.
+These are the functions whose graphs lie above every line segment connecting two points on the graph.
+The natural logarithm is concave, because its second derivative is negative.
+The binary logarithm is a~constant multiple of the natural logarithm, so it must
+be concave, too.
+
+Let us consider graph of a~concave function~$f$ in figure \figref{logavg}.
+We mark points $A=(\alpha,f(\alpha))$ and $B=(\beta,f(\beta))$. We find the
+midpoint~$S$ of the segment~$AB$. Its coordinates are the averages of coordinates
+of the endpoints $A$ and~$B$:
+$$ S = \left({\alpha+\beta\over 2},\, {f(\alpha) + f(\beta)\over 2}\right). $$
+By concavity, the point~$S$ must lie below the graph, so especially below the point
+$$ S' = \left({\alpha+\beta\over 2},\, f\!\left( {\alpha+\beta\over 2} \right) \right). $$
+Comparison of~$y$-coordinates of the points $S$ and~$S'$ yileds the claimed inequality.
+\qed
+
+\figure[logavg]{log-avg.pdf}{}{The mean inequality for a~concave function~$f$}
+
+\corr{
+As $\log{\alpha+\beta\over 2} = \log(\alpha+\beta) - 1$,
+we also have $\log \alpha + \log \beta \le 2\log(\alpha+\beta) - 2$.
+}
+
+\note{
+The lemma also follows by taking logarithms of both sides of the
+Arithmetic Mean -- Geometric Mean inequality
+$ \sqrt{\alpha\beta} \le (\alpha + \beta) / 2 $.
+}
+
+Now we calculate amortized costs of all three types of splay steps.
+In each case, $x$~is the vertex being splayed, $r(x)$ is its rank
+before the step, and $r'(x)$ its rank after the step. We will use
+this the same convention for $s(\cdot)$ and $r(\cdot)$.
+
+\lemman{zig-zag}{
+The amortized cost of a~zig-zag step is at most $3r'(x) - 3r(x)$.
+}
+
+\proof
+Let us follow figure~\figref{splayrot} and consider, how the potential changes
+during the step. The only nodes whose ranks can change are $w$, $x$, and~$y$.
+Thus the potential increases by $(r'(w)-r(w)) + (r'(x)-r(x)) + (r'(y)-r(y))$.
+The real cost of the operation is~2, so the amortized cost becomes:
+$$
+	A = 2 + r'(w) + r'(x) + r'(y) - r(w) - r(x) - r(y).
+$$
+We want to prove that $A \le 3r'(x) - 3r(x)$. We therefore need to bound
+all other ranks using $r(x)$ and $r'(x)$.
+
+We invoke our averaging lemma on the sum $r'(w) + r'(y)$:
+$$\eqalign{
+	r'(w) + r'(y)
+	&= \log m'(w) + \log m'(y) \cr
+	&\le 2\log (m'(w) + m'(y)) - 2.
+}$$
+The subtrees $T'(w)$ and $T'(y)$ are disjoint and they lie below~$x$,
+so we have $\log(m'(w) + m'(y)) \le \log m'(x) = r'(x)$. Thus:
+$$
+	r'(w) + r'(y) \le 2r'(x) - 2.
+$$
+Substituting this to the inequality for~$A$ yields:
+$$
+	A \le 3r'(x) - r(w) - r(x) - r(y).
+$$
+The other ranks can be bounded trivially:
+$$\vbox{\halign{\hfil $#$&${}#$\hfil\quad&because $#$\hfil\cr
+	r(w) &\ge r(x)		&T(w) \supseteq T(x),		\cr
+	r(y) &\ge r(x)		&T(y) \supseteq T(x).		\cr
+}}$$
+Here goes the claim of the lemma.
+\qed
+
+\lemman{zig-zig}{
+The amortized cost of a~zig-zig step is at most $3r'(x) - 3r(x)$.
+}
+
+\proof
+We will follow the same idea as for the zig-zag step. Again, the real cost is~2.
+Ranks can change only at vertices $x$, $y$, and~$z$, so the amortized cost becomes:
+$$
+	A = 2 + r'(x) + r'(y) + r'(z) - r(x) - r(y) - r(z).
+$$
+We want to get rid of all terms except $r(x)$ a~$r'(x)$.
+To achieve this, we would like to invoke the averaging lemma on a~pair of subtrees,
+which are disjoint and their union contains almost all nodes. One such pair is
+$T(x)$ and $T'(z)$:
+$$\eqalign{
+	r(x) + r'(z)
+	&= \log m(x) + \log m'(z) \cr
+	&\le 2\log (m(x)+m'(z)) - 2 \cr
+	&\le 2\log m'(x) - 2 = 2r'(x) - 2. \cr
+}$$
+This is equivalent to the inequality $r'(z) \le 2r'(x) - r(x) - 2$. Thus:
+$$
+	A \le 3r'(x) + r'(y) - 2r(x) - r(y) - r(z).
+$$
+All other terms can be bounded trivially:
+$$\vbox{\halign{\hfil $#$&${}#$\hfil\quad&because $#$\hfil\cr
+	r(z) &= r'(x)		&T(z) = T'(x),			\cr
+	r(y) &\ge r(x)		&T(y) \supseteq T(x),		\cr
+	r'(y) &\le r'(x)	&T'(y) \subseteq T'(x).		\cr
+}}$$
+The claim $A \le 3r'(x) - 3r(x)$ follows.
+\qed
+
+\lemman{zig}{
+The amortized cost of a~zig is at most $3r'(x) - 3r(x) + 1$.
+}
+
+\proof
+The real cost is~1, ranks can change only at vertices $x$ and~$y$,
+so the amortized cost becomes:
+$$
+	A = 1 + r'(x) + r'(y) - r(x) - r(y).
+$$
+By inclusion of subtrees, we have $r'(y) \le r'(x)$ a~$r(y) \ge r(x)$, hence:
+$$
+	A \le 1 + 2r'(x) - 2r(x).
+$$
+It is also clear from inclusion that $r'(x) - r(x)$ must be non-negative,
+so we also have $A \le 1 + 3r'(x) - 3r(x)$ as we wanted.
+\qed
+
+This completes the proof of the previous theorem.
+
+\theorem{
+A~sequence of $m$~\alg{Splay}s on an~$n$-node binary tree runs in time
+$\O((n+m)\log n)$.
+}
+
+\proof
+{\bf TODO!}
+\qed
+
+\exercises
+
+\ex[splaynaive]{Prove that a~naive splay strategy using only single rotations cannot have
+better amortized complexity than $\Omega(n)$. Consider what happens when splaying a~path.}
+
+\endexercises
+
+\section{Search tree operations}
+
+\section{Weighted analysis}
+
+\endchapter
diff --git a/pics/ads.asy b/pics/ads.asy
new file mode 100644
index 0000000..fe9b8f9
--- /dev/null
+++ b/pics/ads.asy
@@ -0,0 +1,184 @@
+/*
+ *  Makra pro Asymptote společná pro všechny obrázky
+ */
+
+void ads_init_pic() {
+	unitsize(1cm);
+}
+
+ads_init_pic();
+
+/*** Základní typy čar a velikosti ***/
+
+pen thin = black + roundcap + 0.2mm;
+pen hair = black + roundcap + 0.1mm;
+pen quarterthick = thin + 0.2mm;
+pen halfthick = thin + 0.4mm;
+pen almostthick = thin + 0.5mm;
+pen thick = thin + 0.6mm;
+defaultpen(thin);
+
+pen shortdashed = linetype(new real[] { 1, 4 });
+pen middashed = linetype(new real[] { 4, 4 });
+pen finedotted = thin + 0.3mm + linetype(new real[] { 0, 2.5 });
+pen agray = gray(0.6);
+pen area_gray = gray(0.75);
+
+// Šířka čáry v uživatelských souřadnicích
+real line_width_user(pen p)
+{
+	pair lw = inverse(currentpicture.scaling()) * (0, linewidth(p));
+	return lw.y;
+}
+
+texpreamble("\font\eightrm=cmr8\font\ninerm=cmr9\font\seventt=cmtt8 at 7pt");
+
+/*** Kreslení grafů ***/
+
+real vertex_size = 0.06;
+arrowbar e_arrow = Arrow(size=7);
+arrowbar e_biarrow = Arrows(size=7);
+arrowbar e_smallarrow = Arrow(size=5);
+arrowbar e_smallbiarrow = Arrows(size=5);
+arrowbar e_miniarrow = Arrow(size=3);
+
+int v_invisible = -1;
+int v_black = 0;
+int v_white = 1;
+int v_gray = 2;
+int v_dashed = 3;
+int v_lightgray = 4;
+int v_bold = 5;
+int v_shadow = 6;
+
+void draw_in_mode(path p, int mode=0)
+{
+	if (mode == v_black)
+		filldraw(p);
+	else if (mode == v_white)
+		filldraw(p, white, black);
+	else if (mode == v_gray)
+		filldraw(p, agray, black);
+	else if (mode == v_dashed)
+		filldraw(p, white, black + shortdashed);
+	else if (mode == v_lightgray)
+		filldraw(p, area_gray, black);
+	else if (mode == v_bold)
+		filldraw(p, white, black + thick);
+	else if (mode == v_shadow)
+		filldraw(p, white, agray);
+}
+
+void vertex(pair p, int mode=0)
+{
+	if (p.x > 100 || p.y > 100) {
+		return;
+	}
+	draw_in_mode(circle(p, vertex_size), mode);
+}
+
+pair current_graph[];
+
+void graph(pair g[], int mode=0)
+{
+	current_graph = g;
+	for (pair p: g) {
+		vertex(p, mode);
+	}
+}
+
+void labeled_graph(pair g[])
+{
+	vertex_size = 0.17;
+	graph(g, 1);
+	for (int i=0; i<g.length; ++i) {
+		if (g[i].x < 100 && g[i].y < 100) {
+			label("\eightrm " + (string) i, g[i]);
+		}
+	}
+}
+
+void vertex(int v, int mode=0)
+{
+	vertex(current_graph[v], mode);
+}
+
+void edge(pair v, pair w, pen p = thin)
+{
+	pair d = unit(w-v);
+	draw((v+d*vertex_size) -- (w-d*vertex_size), p + squarecap);
+}
+
+void edge(int v, int w, pen p = thin)
+{
+	edge(current_graph[v], current_graph[w], p);
+}
+
+void edged(pair v, pair w, pair dv, pair dw, pen p = thin)
+{
+	draw(v + vertex_size*dv {dv} .. {dw} w - vertex_size*dw, p + squarecap);
+}
+
+void edged(int v, int w, pair dv, pair dw, pen p = thin)
+{
+	edged(current_graph[v], current_graph[w], dv, dw, p);
+}
+
+void arc(pair v, pair w, pen p = thin, arrowbar a = e_arrow)
+{
+	pair d = unit(w-v);
+	draw((v+d*vertex_size) -- (w-d*vertex_size), p + squarecap, a);
+}
+
+void arc(int v, int w, pen p = thin, arrowbar a = e_arrow)
+{
+	arc(current_graph[v], current_graph[w], p, a);
+}
+
+void arcd(pair v, pair w, pair dv, pair dw, pen p = thin, arrowbar a = e_arrow)
+{
+	draw(v + vertex_size*dv {dv} .. {dw} w - vertex_size*dw, p + squarecap, a);
+}
+
+void arcd(int v, int w, pair dv, pair dw, pen p = thin, arrowbar a = e_arrow)
+{
+	arcd(current_graph[v], current_graph[w], dv, dw, p, a);
+}
+
+void selfloop(pair v, int d, pen p = thin)
+{
+	draw(v + vertex_size*dir(d+45) {dir(d+45)} .. v + 3*vertex_size*dir(d) .. {-dir(d-45)} v + vertex_size*dir(d-45), p + squarecap, e_arrow);
+}
+
+void selfloop(int v, int d, pen p = thin)
+{
+	selfloop(current_graph[v], d, p);
+}
+
+/*** Geometrie ***/
+
+void fpoint(pair p)
+{
+	fill(circle(p, 0.08));
+}
+
+void epoint(pair p)
+{
+	filldraw(circle(p, 0.08), white, black);
+}
+
+/*** Dílčí obrázky ***/
+
+picture ads_sub_pic()
+{
+	picture p = new picture;
+	currentpicture = p;
+	ads_init_pic();
+	return p;
+}
+
+frame centered(picture p)
+{
+	frame f = p.fit();
+	return align(f, (0,0));
+}
diff --git a/pics/pdftex b/pics/pdftex
new file mode 100755
index 0000000..18c7b2b
--- /dev/null
+++ b/pics/pdftex
@@ -0,0 +1,3 @@
+#!/bin/bash
+# pdftex wrapper to make Asymptote use csplain
+exec /usr/bin/pdftex -output-format pdf -fmt pdfcsplain "$@"
diff --git a/pics/trees.asy b/pics/trees.asy
new file mode 100644
index 0000000..d04b958
--- /dev/null
+++ b/pics/trees.asy
@@ -0,0 +1,192 @@
+/* Společné funkce pro kreslení stromů všeho druhu */
+
+import ads;
+
+pair bst_edge = (0, -1);
+pair bst_mini = (0, 0.5);
+
+real tree_node_size = 0.2;
+real tree_sub_size = 0.23;
+real tree_sub_aspect = 1;
+pair tree_label_offset = (0,0);
+
+void tree_init(pair g[])
+{
+	current_graph = g;
+	vertex_size = tree_node_size;
+}
+
+void tree_node(int i, string name = "", int mode=1)
+{
+	vertex(i, mode);
+	label("\strut $" + name + "$", current_graph[i] + tree_label_offset);
+}
+
+void tree_num(int i, int x, int mode=1)
+{
+	vertex(i, mode);
+	label("$" + (string) x + "$", current_graph[i] + tree_label_offset);
+}
+
+void tree_num_inverse(int i, int x)
+{
+	vertex(i, 0);
+	label("$" + (string) x + "$", current_graph[i] + tree_label_offset, white);
+}
+
+void tree_ext(int i, real size=0.5, int mode=1)
+{
+	pair p = current_graph[i];
+	path v = shift(p - size*(vertex_size, vertex_size)) * scale(size*2*vertex_size) * unitsquare;
+	draw_in_mode(v, mode);
+}
+
+void tree_sub(int i, string name = "")
+{
+	pair p = current_graph[i];
+	real vsize = tree_sub_size * tree_sub_aspect;
+	draw(p -- p + (-1.5*tree_sub_size, -3*vsize) -- p + (1.5*tree_sub_size, -3*vsize) -- cycle);
+	label("\ninerm " + name, p + (0, -2*vsize));
+}
+
+void tree_elliptic_node(int i, string name = "", real elong=1, int mode=1)
+{
+	pair p = current_graph[i];
+	real h = vertex_size;
+	real w = elong*vertex_size;
+	draw_in_mode(
+		arc(p-(w,0), h, 90, 270) --
+		arc(p+(w,0), h, -90, 90) --
+		cycle,
+		mode
+	);
+	label("\strut $" + name + "$", p - (0, 0.02) + tree_label_offset);
+}
+
+void tree_edge(int i, int j, pen p = thin)
+{
+	draw(current_graph[i] -- current_graph[j], p);
+}
+
+/* AVL stromy */
+
+void lbracket(real x, real ytop, real ybot, string name, real lpos = 0.5)
+{
+	pair t = (x, ytop);
+	pair b = (x, ybot);
+	draw(t -- t-(0.1,0) -- b-(0.1,0) -- b);
+	label("$" + name + "$", point(t--b, lpos), 2*W);
+}
+
+void rbracket(real x, real ytop, real ybot, string name, real lpos = 0.5)
+{
+	pair t = (x, ytop);
+	pair b = (x, ybot);
+	draw(t -- t+(0.1,0) -- b+(0.1,0) -- b);
+	label("$" + name + "$", point(t--b, lpos), 2*E);
+}
+
+real br_top_vertex(int i)
+{
+	return current_graph[i].y + 1.2*vertex_size;
+}
+
+real br_bot_sub(int i)
+{
+	return current_graph[i].y - 3.5*tree_sub_size;
+}
+
+void tree_sub_ht(int i, string name = "", string ht)
+{
+	tree_sub(i, name);
+	label("$" + ht + "$", current_graph[i] + 3*tree_sub_size*tree_sub_aspect*S, S);
+}
+
+/* (a,b)-stromy */
+
+void ab_edge(int i, int j, real delta = 0, pen p = thin)
+{
+	draw(current_graph[i] + (delta,0) -- current_graph[j], p);
+}
+
+/* LLRB stromy */
+
+pen rb_red = cmyk(0, 0.9, 0.7, 0.2) + colorless(halfthick);
+pen rb_black = gray(0) + halfthick;
+pen rb_any = agray + halfthick;
+
+/* Úplné binarní stromy */
+
+pair [] complete_binary_tree(real width, real spread, int depth)
+{
+	pair u[];
+	u[0] = (0,0);
+	u[1] = (0,0);
+	int r = 1;
+	int w = 2;
+	for (int i=1; i<depth; ++i) {
+		real d = width / 2**i;
+		for (int j=0; j<2**(i-1); ++j) {
+			u[w] = u[r] - (d,spread);
+			u[w+1] = u[r] + (d,-spread);
+			w += 2;
+			++r;
+		}
+	}
+	return u;
+}
+
+/* Pohodlnější konstrukce stromů */
+
+struct tnode {
+	int id;
+	pair pos;
+	pair direction;
+	tnode parent;
+	tnode sons[];
+	int size;
+	int mode;		// Drawing mode
+	void draw_vertex(tnode w) { vertex(w.id, mode=this.mode); }
+	void draw_edge(tnode w) { if (w.parent != null) tree_edge(w.parent.id, this.id); }
+};
+
+tnode tnodes[];
+pair tn_pos[];
+pair tn_ref;
+real tn_edge_len = 1;
+
+void tn_init(pair refpos=(0,0))
+{
+	tnodes = new tnode[];
+	tn_pos = new pair[];
+	tn_ref = refpos;
+	tree_init(tn_pos);
+}
+
+tnode tn_add(int parent_id, real angle)
+{
+	tnode v;
+	v.id = tnodes.length;
+	v.sons = new tnode[];
+	v.mode = v_white;
+	tnodes.push(v);
+	pair d = (0,1) * dir(angle);
+	d = d * (-tn_edge_len/d.y);
+	if (parent_id < 0) {
+		v.pos = tn_ref;
+	} else {
+		v.parent = tnodes[parent_id];
+		v.parent.sons.push(v);
+		v.pos = v.parent.pos + d;
+	}
+	tn_pos.push(v.pos);
+	return v;
+}
+
+void tn_draw()
+{
+	for (tnode v: tnodes)
+		v.draw_edge(v);
+	for (tnode v: tnodes)
+		v.draw_vertex(v);
+}
diff --git a/tex/adsmac.tex b/tex/adsmac.tex
index 6c83007..3162d5b 100644
--- a/tex/adsmac.tex
+++ b/tex/adsmac.tex
@@ -98,13 +98,9 @@
 \prenesteditemizeskip=\smallskipamount
 \postnesteditemizeskip=\smallskipamount
 
-\let\ucwitemize=\itemize
-\def\itemize{\preitemizeskip=0pt\interitemskip=\medskipamount\ucwitemize}
-\def\tightitemize{\preitemizeskip=\dimexpr\medskipamount-\smallskipamount\relax\interitemskip=\smallskipamount\ucwitemize}
-
-\let\ucwnumlist=\numlist
-\def\numlist{\preitemizeskip=0pt\interitemskip=\medskipamount\ucwnumlist}
-\def\tightnumlist{\preitemizeskip=\dimexpr\medskipamount-\smallskipamount\relax\interitemskip=\smallskipamount\ucwnumlist}
+\let\ucwlist=\list
+\def\list{\preitemizeskip=0pt\interitemskip=\medskipamount\ucwlist}
+\def\tightlist{\preitemizeskip=\dimexpr\medskipamount-\smallskipamount\relax\interitemskip=\smallskipamount\ucwlist}
 
 \abovedisplayskip=\bigskipamount
 \abovedisplayshortskip=\abovedisplayskip
@@ -282,7 +278,7 @@
 \def\sepfont{\setfonts[LMRoman/30]\bf}
 \def\pagenumfont{\setfonts[LMRoman/10]\rm}
 
-\protected\def\captionfont{\setfonts[Montserrat/9]\setmath[//]\fixsetmath\baselineskip=11bp}
+\protected\def\captionfont{\setfonts[LMSans/9]\setmath[//]\fixsetmath\baselineskip=11bp}
 
 %%% Nepovinné argumenty %%%
 
-- 
GitLab