canuc80k1601·2/50

Tổng Đoạn Động

Nộp bài trên LQDOJ

Bài 16 · Fenwick Tree

Cho một mảng số nguyên gồm phần tử, đánh số từ đến . Hãy xử lý thao tác theo đúng thứ tự:

  • : gán giá trị mới ;
  • : tính tổng .

Input

  • Dòng đầu chứa hai số nguyên và .
  • Dòng thứ hai chứa số nguyên .
  • Mỗi trong dòng tiếp theo mô tả một thao tác theo một trong hai dạng trên.

Output

  • Với mỗi thao tác loại , in tổng của đoạn được hỏi trên một dòng.

Constraints

  • .
  • .
  • .
  • .
  • Mọi tổng đều nằm trong miền của số nguyên có dấu -bit.

Scoring

  • Subtask ( số điểm): .
  • Subtask ( số điểm): Không có giới hạn bổ sung.

Example

Test 1

Input

5 6
2 1 4 3 5
2 2 4
1 3 9
2 1 3
1 1 10
2 1 5
2 4 4

Output

8
12
28
3

Giải thích: Ban đầu đoạn có tổng . Sau hai phép gán, mảng trở thành , nên tổng toàn mảng là và đoạn có giá trị .

Lời giải tóm tắt
  • Phân tích: Fenwick Tree thuận tiện cho phép cộng tại một vị trí, trong khi thao tác của đề là gán. Ta giữ thêm mảng giá trị hiện tại để đổi một phép gán thành một lượng chênh lệch.
  • Phân tích: Nếu a[k] đang bằng old và cần gán thành u, tổng của mọi đoạn chứa k phải thay đổi thêm u-old. Vì vậy chỉ cần cộng u-old tại vị trí k trong Fenwick.
  • Thuật toán: Khởi tạo Fenwick bằng n giá trị ban đầu và giữ chúng trong mảng a.
  • Thuật toán: Với thao tác 1 k u:
  • Thuật toán: tính delta = u-a[k];
  • Thuật toán: cộng delta vào vị trí k của Fenwick;
  • Thuật toán: gán a[k]=u.
  • Thuật toán: Với thao tác 2 l r, in prefix(r) - prefix(l-1).
  • Chứng minh: Ta chứng minh bất biến: sau mỗi thao tác, tổng tiền tố do Fenwick trả về bằng tổng tiền tố của mảng hiện tại.
  • Chứng minh: Bất biến đúng sau khởi tạo. Một phép gán chỉ thay đổi a[k] một lượng delta; cập nhật Fenwick cũng cộng đúng delta tại k, nên mọi tiền tố chứa k thay đổi đúng lượng đó và các tiền tố còn lại không đổi. Do đó bất biến được duy trì.
  • Chứng minh: Từ bất biến, prefix(r)-prefix(l-1) loại bỏ các phần tử trước l và còn lại đúng tổng a[l..r]. Vì vậy thuật toán trả lời đúng mọi truy vấn.
  • Độ phức tạp: Khởi tạo mất O(n log n). Mỗi thao tác mất O(log n), nên tổng thời gian là O((n+q) log n) và bộ nhớ là O(n).