-
Notifications
You must be signed in to change notification settings - Fork 20
/
mo.lisp
95 lines (86 loc) · 3.79 KB
/
mo.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
;;;
;;; Mo's algorithm
;;;
(defpackage :cp/mo
(:use :cl)
(:export #:mo-integer #:mo #:make-mo #:mo-get-current #:mo-get-previous
#:mo-process2 #:mo-process4))
(in-package :cp/mo)
(deftype mo-integer () 'fixnum)
(defstruct (mo (:constructor %make-mo
(lefts rights order width))
(:conc-name %mo-)
(:copier nil)
(:predicate nil))
(lefts nil :type (simple-array mo-integer (*)))
(rights nil :type (simple-array mo-integer (*)))
(order nil :type (simple-array (integer 0 #.most-positive-fixnum) (*)))
(width 0 :type (integer 0 #.most-positive-fixnum))
(index 0 :type (integer 0 #.most-positive-fixnum))
(posl 0 :type mo-integer)
(posr 0 :type mo-integer))
(defun make-mo (bucket-width lefts rights)
"LEFTS := vector of indices of left-end of queries (inclusive)
RIGHTS := vector of indices of right-end of queries (exclusive)
BUCKET-WIDTH would be better set to N/sqrt(Q) where N is the width of the
universe and Q is the number of queries."
(declare (optimize (speed 3))
((simple-array mo-integer (*)) lefts rights)
((mod #.array-dimension-limit) bucket-width)
(inline sort))
(let* ((q (length lefts))
(order (make-array q :element-type '(integer 0 #.most-positive-fixnum))))
(assert (= q (length rights)))
(dotimes (i q) (setf (aref order i) i))
(setf order (sort order
(lambda (x y)
(if (= (floor (aref lefts x) bucket-width)
(floor (aref lefts y) bucket-width))
;; Even-number [Odd-number] block is in ascending
;; [descending] order w.r.t. the right end.
(if (evenp (floor (aref lefts x) bucket-width))
(< (aref rights x) (aref rights y))
(> (aref rights x) (aref rights y)))
(< (aref lefts x) (aref lefts y))))))
(%make-mo lefts rights order bucket-width)))
(declaim (inline mo-get-current))
(defun mo-get-current (mo)
"Returns the original index of the current (not yet proessed) query."
(aref (%mo-order mo) (%mo-index mo)))
(declaim (inline mo-get-previous))
(defun mo-get-previous (mo)
"Returns the original index of the previous (= last processed) query. Returns
the initial index instead when no queries are processed yet."
(aref (%mo-order mo) (max 0 (- (%mo-index mo) 1))))
(declaim (inline mo-process4))
(defun mo-process4 (mo extend-l extend-r shrink-l shrink-r)
"Processes the next query. EXTEND and SHRINK take three arguments: the <index>
added/removed right now, and both ends of the next range: [<left>, <right>)"
(declare (function extend-l extend-r shrink-l shrink-r))
(let* ((ord (mo-get-current mo))
(left (aref (%mo-lefts mo) ord))
(right (aref (%mo-rights mo) ord))
(posl (%mo-posl mo))
(posr (%mo-posr mo)))
(declare ((mod #.array-dimension-limit) posl posr))
(loop while (< left posl)
do (decf posl)
(funcall extend-l posl posl posr))
(loop while (< posr right)
do (funcall extend-r posr posl (+ posr 1))
(incf posr))
(loop while (< posl left)
do (funcall shrink-l posl (+ posl 1) posr)
(incf posl))
(loop while (< right posr)
do (decf posr)
(funcall shrink-r posr posl posr))
(setf (%mo-posl mo) posl
(%mo-posr mo) posr)
(incf (%mo-index mo))))
(declaim (inline mo-process2))
(defun mo-process2 (mo extend shrink)
"Processes the next query. EXTEND and SHRINK take three arguments: the <index>
added/removed right now, and both ends of the next range: [<left>, <right>)"
(declare (function extend shrink))
(mo-process4 mo extend extend shrink shrink))