00-把一段话翻过来.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. #!/usr/bin/env python3
  2. """课前零食:带双哨兵、rev Lazy 的隐式 Splay 小实验室。"""
  3. from __future__ import annotations
  4. from dataclasses import dataclass
  5. @dataclass
  6. class Node:
  7. label: str
  8. value: int
  9. left: Node | None = None
  10. right: Node | None = None
  11. parent: Node | None = None
  12. size: int = 1
  13. total: int = 0
  14. rev: bool = False
  15. def __post_init__(self) -> None:
  16. self.total = self.value
  17. def node_size(node: Node | None) -> int:
  18. return node.size if node else 0
  19. def node_sum(node: Node | None) -> int:
  20. return node.total if node else 0
  21. class SequenceSplay:
  22. def __init__(self) -> None:
  23. self.model = list("ABCDEF")
  24. labels = ["L"] + self.model + ["R"]
  25. values = [0, 10, 20, 30, 40, 50, 60, 0]
  26. nodes = [Node(label, value) for label, value in zip(labels, values)]
  27. self.root = self.build_balanced(nodes)
  28. def build_balanced(self, nodes: list[Node]) -> Node | None:
  29. if not nodes:
  30. return None
  31. middle = len(nodes) // 2
  32. root = nodes[middle]
  33. root.left = self.build_balanced(nodes[:middle])
  34. root.right = self.build_balanced(nodes[middle + 1 :])
  35. if root.left:
  36. root.left.parent = root
  37. if root.right:
  38. root.right.parent = root
  39. self.pull(root)
  40. return root
  41. def pull(self, node: Node | None) -> None:
  42. if node:
  43. node.size = 1 + node_size(node.left) + node_size(node.right)
  44. node.total = node.value + node_sum(node.left) + node_sum(node.right)
  45. def apply_rev(self, node: Node | None) -> None:
  46. if node is None:
  47. return
  48. node.left, node.right = node.right, node.left
  49. node.rev = not node.rev
  50. def push(self, node: Node | None) -> None:
  51. if node and node.rev:
  52. self.apply_rev(node.left)
  53. self.apply_rev(node.right)
  54. node.rev = False
  55. def push_path(self, node: Node) -> None:
  56. chain: list[Node] = []
  57. current: Node | None = node
  58. while current:
  59. chain.append(current)
  60. current = current.parent
  61. for ancestor in reversed(chain):
  62. self.push(ancestor)
  63. def is_right(self, node: Node) -> bool:
  64. return node.parent is not None and node.parent.right is node
  65. def rotate(self, node: Node, log: list[str]) -> None:
  66. parent = node.parent
  67. if parent is None:
  68. return
  69. grand = parent.parent
  70. if node is parent.left:
  71. middle = node.right
  72. node.right = parent
  73. parent.left = middle
  74. direction = "右旋"
  75. else:
  76. middle = node.left
  77. node.left = parent
  78. parent.right = middle
  79. direction = "左旋"
  80. if middle:
  81. middle.parent = parent
  82. parent.parent = node
  83. node.parent = grand
  84. if grand is None:
  85. self.root = node
  86. elif parent is grand.left:
  87. grand.left = node
  88. else:
  89. grand.right = node
  90. self.pull(parent)
  91. self.pull(node)
  92. log.append(f"{direction}:{node.label} 绕 {parent.label}。")
  93. def splay(self, node: Node, goal: Node | None, log: list[str]) -> None:
  94. self.push_path(node)
  95. while node.parent is not goal:
  96. parent = node.parent
  97. if parent is None:
  98. break
  99. grand = parent.parent
  100. if grand is goal:
  101. self.rotate(node, log)
  102. elif self.is_right(node) == self.is_right(parent):
  103. self.rotate(parent, log)
  104. self.rotate(node, log)
  105. else:
  106. self.rotate(node, log)
  107. self.rotate(node, log)
  108. def kth(self, rank: int) -> Node:
  109. if not 1 <= rank <= node_size(self.root):
  110. raise ValueError("排名越界")
  111. current = self.root
  112. while current:
  113. self.push(current)
  114. left_count = node_size(current.left)
  115. if rank <= left_count:
  116. current = current.left
  117. elif rank == left_count + 1:
  118. return current
  119. else:
  120. rank -= left_count + 1
  121. current = current.right
  122. raise RuntimeError("size 账本损坏")
  123. def expose(self, left: int, right: int) -> tuple[Node, Node, Node, list[str]]:
  124. if not (1 <= left <= right <= len(self.model)):
  125. raise ValueError("区间应满足 1 ≤ l ≤ r ≤ 当前长度")
  126. log: list[str] = []
  127. x = self.kth(left)
  128. log.append(f"x=kth({left})={x.label},先伸到根。")
  129. self.splay(x, None, log)
  130. y = self.kth(right + 2)
  131. log.append(f"y=kth({right + 2})={y.label},再伸到 x 的右儿子位置。")
  132. self.splay(y, x, log)
  133. mid = y.left
  134. if mid is None:
  135. raise RuntimeError("合法非空区间不应暴露为空")
  136. return x, y, mid, log
  137. def reverse(self, left: int, right: int) -> list[str]:
  138. x, y, mid, log = self.expose(left, right)
  139. self.apply_rev(mid)
  140. self.pull(y)
  141. self.pull(x)
  142. self.model[left - 1 : right] = reversed(self.model[left - 1 : right])
  143. log.append(f"对 y.left={mid.label} 的子树 apply_rev;不逐项移动字符。")
  144. return log
  145. def interval_sum(self, left: int, right: int) -> tuple[int, list[str]]:
  146. _, _, mid, log = self.expose(left, right)
  147. log.append(f"读取 mid.sum={mid.total}。")
  148. return mid.total, log
  149. def inorder_nodes(self, node: Node | None = None, top: bool = True) -> list[Node]:
  150. if top:
  151. node = self.root
  152. if node is None:
  153. return []
  154. self.push(node)
  155. return self.inorder_nodes(node.left, top=False) + [node] + self.inorder_nodes(node.right, top=False)
  156. def body_labels(self) -> list[str]:
  157. return [node.label for node in self.inorder_nodes()[1:-1]]
  158. def body_values(self) -> list[int]:
  159. return [node.value for node in self.inorder_nodes()[1:-1]]
  160. def show(self) -> None:
  161. nodes = self.inorder_nodes()
  162. print("完整中序:", " ".join(node.label for node in nodes))
  163. print("正文:", " ".join(self.body_labels()))
  164. print("正文数值:", self.body_values())
  165. print("提示:L、R 只占位置,不计正文答案。")
  166. def check(self) -> tuple[bool, str]:
  167. def dfs(node: Node | None, parent: Node | None) -> tuple[bool, int, int, str]:
  168. if node is None:
  169. return True, 0, 0, ""
  170. self.push(node)
  171. if node.parent is not parent:
  172. return False, 0, 0, f"{node.label} 的 parent 指针错误"
  173. ok_l, left_size, left_sum, why = dfs(node.left, node)
  174. if not ok_l:
  175. return False, 0, 0, why
  176. ok_r, right_size, right_sum, why = dfs(node.right, node)
  177. if not ok_r:
  178. return False, 0, 0, why
  179. expected_size = left_size + 1 + right_size
  180. expected_sum = left_sum + node.value + right_sum
  181. if node.size != expected_size or node.total != expected_sum:
  182. return False, 0, 0, f"{node.label} 的 size/sum 摘要错误"
  183. return True, expected_size, expected_sum, ""
  184. ok, _, _, why = dfs(self.root, None)
  185. if not ok:
  186. return False, why
  187. if self.body_labels() != self.model:
  188. return False, f"树中正文 {self.body_labels()} 与列表验算 {self.model} 不同"
  189. return True, "parent、size、sum、Lazy 后的逻辑序列均正确"
  190. def print_log(log: list[str]) -> None:
  191. for line in log:
  192. print(" ", line)
  193. def warmup() -> None:
  194. print("=== 任务 0:先预测双哨兵的夹子 ===")
  195. print("正文为 A B C D E F,目标区间是 [2,5]。")
  196. try:
  197. input("请先写 x=kth(l) 和 y=kth(r+2) 分别是谁,再按回车: ")
  198. except EOFError:
  199. pass
  200. print("核对:x=A,y=F;B,C,D,E 会成为 y.left。")
  201. def main() -> None:
  202. sequence = SequenceSplay()
  203. print("文艺平衡树小实验室:隐式 Splay + 双哨兵 + rev Lazy。")
  204. warmup()
  205. sequence.show()
  206. print("\n命令:show;expose 2 5;rev 2 5;sum 2 5;check;q。")
  207. while True:
  208. try:
  209. raw = input("\n> ").strip()
  210. except EOFError:
  211. raw = "q"
  212. if not raw or raw in {"q", "quit", "exit"}:
  213. return
  214. parts = raw.split()
  215. try:
  216. if parts == ["show"]:
  217. sequence.show()
  218. elif parts == ["check"]:
  219. ok, message = sequence.check()
  220. print("通过:" if ok else "失败:", message)
  221. elif len(parts) == 3 and parts[0] == "expose":
  222. left, right = int(parts[1]), int(parts[2])
  223. x, y, mid, log = sequence.expose(left, right)
  224. print_log(log)
  225. print(f"暴露完成:x={x.label},y={y.label},y.left 的根是 {mid.label}。")
  226. print("y.left 的中序:", " ".join(node.label for node in sequence.inorder_nodes(mid, top=False)))
  227. elif len(parts) == 3 and parts[0] == "rev":
  228. print_log(sequence.reverse(int(parts[1]), int(parts[2])))
  229. sequence.show()
  230. elif len(parts) == 3 and parts[0] == "sum":
  231. answer, log = sequence.interval_sum(int(parts[1]), int(parts[2]))
  232. print_log(log)
  233. print("区间和:", answer)
  234. else:
  235. raise ValueError
  236. except ValueError as error:
  237. print("小提示:", error or "试试 rev 2 5。")
  238. if __name__ == "__main__":
  239. main()