00-会变化的区间和.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #!/usr/bin/env python3
  2. """课前零食:在同一数组上观察 Fenwick 与线段树的区间摘要。"""
  3. from __future__ import annotations
  4. DEFAULT = [3, 1, 4, 1, 5, 9]
  5. def ask(prompt: str, default: str = "q") -> str:
  6. try:
  7. return input(prompt).strip() or default
  8. except EOFError:
  9. return default
  10. def lowbit(value: int) -> int:
  11. return value & -value
  12. class Fenwick:
  13. def __init__(self, values: list[int]) -> None:
  14. self.n = len(values)
  15. self.tree = [0] * (self.n + 1)
  16. for index, value in enumerate(values, 1):
  17. self.add(index, value, quiet=True)
  18. def add(self, index: int, delta: int, quiet: bool = False) -> None:
  19. touched: list[int] = []
  20. while index <= self.n:
  21. self.tree[index] += delta
  22. touched.append(index)
  23. index += lowbit(index)
  24. if not quiet:
  25. print("Fenwick 更新的摘要下标:", touched)
  26. def prefix(self, index: int) -> int:
  27. answer = 0
  28. blocks: list[tuple[int, int]] = []
  29. while index > 0:
  30. answer += self.tree[index]
  31. blocks.append((index - lowbit(index) + 1, index))
  32. index -= lowbit(index)
  33. print("Fenwick 用到的块:", blocks)
  34. return answer
  35. def show(self) -> None:
  36. for index in range(1, self.n + 1):
  37. left = index - lowbit(index) + 1
  38. print(f"tree[{index}]={self.tree[index]:>2},负责 [{left},{index}]")
  39. class SegmentTree:
  40. def __init__(self, values: list[int]) -> None:
  41. self.n = 1
  42. while self.n < len(values):
  43. self.n *= 2
  44. self.tree = [0] * (2 * self.n)
  45. self.tree[self.n:self.n + len(values)] = values
  46. for index in range(self.n - 1, 0, -1):
  47. self.tree[index] = self.tree[index * 2] + self.tree[index * 2 + 1]
  48. def set(self, index: int, value: int) -> None:
  49. node = self.n + index - 1
  50. self.tree[node] = value
  51. touched = [node]
  52. node //= 2
  53. while node:
  54. self.tree[node] = self.tree[node * 2] + self.tree[node * 2 + 1]
  55. touched.append(node)
  56. node //= 2
  57. print("线段树向上重算的节点:", touched)
  58. def query(self, left: int, right: int) -> int:
  59. left += self.n - 1
  60. right += self.n - 1
  61. answer = 0
  62. used: list[int] = []
  63. while left <= right:
  64. if left % 2 == 1:
  65. answer += self.tree[left]
  66. used.append(left)
  67. left += 1
  68. if right % 2 == 0:
  69. answer += self.tree[right]
  70. used.append(right)
  71. right -= 1
  72. left //= 2
  73. right //= 2
  74. print("线段树直接拿到的节点:", used)
  75. return answer
  76. def main() -> None:
  77. values = DEFAULT[:]
  78. fenwick = Fenwick(values)
  79. segment = SegmentTree(values)
  80. print("初始数组(下标从 1):", values)
  81. print("命令:sum l r;set i x;show;q。直接回车退出。")
  82. while True:
  83. command = ask("\n> ")
  84. if command in {"q", "quit", "exit"}:
  85. break
  86. parts = command.split()
  87. try:
  88. if parts[0] == "show":
  89. fenwick.show()
  90. elif parts[0] == "sum" and len(parts) == 3:
  91. left, right = map(int, parts[1:])
  92. if not (1 <= left <= right <= len(values)):
  93. raise ValueError("下标应在数组范围内")
  94. fenwick_answer = fenwick.prefix(right) - fenwick.prefix(left - 1)
  95. segment_answer = segment.query(left, right)
  96. print(f"区间 [{left},{right}]:Fenwick={fenwick_answer},线段树={segment_answer}")
  97. elif parts[0] == "set" and len(parts) == 3:
  98. index, value = map(int, parts[1:])
  99. if not 1 <= index <= len(values):
  100. raise ValueError("下标应在数组范围内")
  101. delta = value - values[index - 1]
  102. values[index - 1] = value
  103. fenwick.add(index, delta)
  104. segment.set(index, value)
  105. print("新数组:", values)
  106. else:
  107. raise ValueError("命令格式不对")
  108. except (ValueError, IndexError) as error:
  109. print("小提示:", error)
  110. if __name__ == "__main__":
  111. main()