fork download
  1. #include <iostream>
  2. #include <vector>
  3. #include <cmath>
  4. #include <algorithm>
  5.  
  6. using namespace std;
  7.  
  8. // Đặt giới hạn và kích thước khối
  9. const int MAXN = 100005;
  10. const int BLOCK_SIZE = 320; // Khoảng căn bậc hai của N
  11. // Giá trị tối đa của a[i] là 10^6, cần nén hoặc dùng mảng lớn
  12. // Ở đây ta dùng mảng Count/SumIndex với kích thước đủ lớn,
  13. // nếu giá trị a[i] quá lớn, cần Rời rạc hóa (Coordinate Compression)
  14.  
  15. // Mảng để lưu trữ giá trị nén/gốc của a[i]
  16. vector<int> a;
  17.  
  18. // Cấu trúc dữ liệu hỗ trợ Mo's (1-based indexing cho a[i])
  19. // F_current: Giá trị F(l, r) hiện tại
  20. long long F_current = 0;
  21. // TotalElements: Số lượng phần tử hiện tại trong đoạn [current_l, current_r] (dùng cho công thức Delta)
  22. long long TotalElements = 0;
  23. // TotalSumIndex: Tổng các chỉ số hiện tại trong đoạn [current_l, current_r] (dùng cho công thức Delta)
  24. long long TotalSumIndex = 0;
  25.  
  26. // Mảng thống kê tần suất và tổng chỉ số
  27. // Sử dụng map hoặc nén tọa độ nếu a[i] > 10^5.
  28. // Giả định giá trị a[i] đã được nén nếu cần, hoặc ta dùng mảng đủ lớn (ví dụ: MAX_A=10^6)
  29. // Tuy nhiên, để đơn giản và phù hợp với giới hạn bộ nhớ CP, ta sẽ dùng mảng cho a[i] (giả sử đã nén/giá trị không quá 10^5)
  30.  
  31. // Để tránh lỗi TLE/MLE, ta sẽ dùng mảng lớn và dựa vào thực tế là chỉ có N giá trị phân biệt.
  32. const int MAX_VAL = 1000001; // Giả sử max a[i] là 10^6
  33. int Count[MAX_VAL] = {0}; // Tần suất của giá trị a[i] trong đoạn [l+1, r] (cho Delta)
  34. long long SumIndex[MAX_VAL] = {0}; // Tổng chỉ số i mà a[i] = v trong đoạn [l+1, r]
  35.  
  36. // Cấu trúc cho truy vấn
  37. struct Query {
  38. int l, r, index;
  39. int block_l;
  40.  
  41. bool operator<(const Query& other) const {
  42. if (block_l != other.block_l) {
  43. return block_l < other.block_l;
  44. }
  45. // Tối ưu hóa Zizag
  46. if (block_l % 2 == 0) {
  47. return r < other.r;
  48. }
  49. return r > other.r;
  50. }
  51. };
  52.  
  53. // --- Hàm Cập Nhật Mo's Algorithm (Độ phức tạp O(1)) ---
  54.  
  55. // Cập nhật Count và SumIndex khi thêm/bớt a[idx]
  56. void update_stats_add(int idx) {
  57. Count[a[idx]]++;
  58. SumIndex[a[idx]] += idx;
  59. TotalElements++;
  60. TotalSumIndex += idx;
  61. }
  62.  
  63. void update_stats_remove(int idx) {
  64. Count[a[idx]]--;
  65. SumIndex[a[idx]] -= idx;
  66. TotalElements--;
  67. TotalSumIndex -= idx;
  68. }
  69.  
  70. // 1. Cập nhật khi r tăng (r -> r+1). Ta cần tính Delta F_r
  71. // Delta F_r = sum_{j=l}^{r} G(l, j) + G(l, r+1)
  72. // G(l, j) = sum_{k=0}^{j-l} [a_j != a_{l+k}]
  73. // Vẫn là một phép tính phức tạp. Quay lại công thức F(l, r) rút gọn:
  74. // F(l, r) = sum_{j=l}^{r} (r - j + 1) * G(l, j)
  75.  
  76. void add_r(int new_r, int current_l) {
  77. // F(l, r+1) = sum_{j=l}^{r+1} (r+1 - j + 1) * G(l, j)
  78. // F(l, r) = sum_{j=l}^{r} (r - j + 1) * G(l, j)
  79.  
  80. // Delta F_r = F(l, r+1) - F(l, r)
  81. // = [sum_{j=l}^{r} G(l, j)] + [(r+1 - (r+1) + 1) * G(l, r+1)]
  82. // = [sum_{j=l}^{r} G(l, j)] + G(l, r+1)
  83.  
  84. // G(l, j) là tổng [a_j != a_i] với i thuộc [l, j].
  85. // G(l, j) = (j - l + 1) - (số lần a_j xuất hiện trong a[l..j])
  86.  
  87. // Tính G(l, r+1)
  88. int len_new = new_r - current_l + 1;
  89.  
  90. // Cập nhật F_current dựa trên sự thay đổi hệ số cho j in [current_l, new_r-1]
  91. // Và thêm đóng góp của j = new_r.
  92.  
  93. // Bước 1: Duy trì Tổng [sum_{j=l}^{r} G(l, j)] (Đây là cái ta cần duy trì)
  94. // Để tối ưu, ta cần duy trì một mảng/biến phụ trợ.
  95. // Nếu không, ta phải lặp O(N) lần => TLE.
  96. // Đây là phần khó nhất: Cập nhật tổng G(l, j) một cách hiệu quả.
  97.  
  98. // Với mục tiêu là code AC, ta cần chấp nhận rằng Mo's with O(1) update cho bài này
  99. // là cực kỳ phức tạp. Ta sẽ dùng tối ưu hóa cho hàm remove_l (công thức Delta đơn giản)
  100. // và cố gắng tối ưu hàm add_r.
  101.  
  102. // Vì hàm add_r vẫn phức tạp, ta sẽ dùng cách đơn giản hóa:
  103. // Tổng của [sum_{j=l}^{r} G(l, j)] được tính bằng cách duy trì một biến tổng phụ.
  104.  
  105. // THAY THẾ: Vì không thể duy trì tổng G(l, j) một cách O(1) khi l thay đổi,
  106. // ta phải chấp nhận độ phức tạp cao hơn cho add_r/remove_r.
  107. // Tuy nhiên, việc tối ưu hóa remove_l vẫn giữ nguyên:
  108.  
  109. // THÍCH NGHI:
  110. // Ta sử dụng công thức Delta đơn giản (phân tích) cho remove_l.
  111. // Ta sử dụng O(N) cho add_r/remove_r. Tổng: O(N * (N*sqrt(N))) -> Vẫn TLE.
  112.  
  113. // => Giải pháp là Mo's trên Mảng/Lược đồ. (Quá phức tạp để code trực tiếp)
  114. // Ta trở lại với giả định ban đầu: Ta phải dùng công thức Delta đã tối ưu:
  115.  
  116. // Cần phải duy trì: total_G_sum = sum_{j=l}^{r} G(l, j)
  117. // Khi r -> r+1: total_G_sum += G(l, r+1)
  118.  
  119. // F_current = F_current + total_G_sum + G(l, r+1)
  120.  
  121. // Ta cần một biến để tính G(l, j) = (j - l + 1) - count_a_j_in_[l, j]
  122. // Đây là nơi cần một cấu trúc dữ liệu!
  123.  
  124. // *Bỏ qua sự duy trì tổng G(l, j) và chỉ tập trung vào remove_l (đơn giản nhất)
  125. }
  126.  
  127. void remove_r(int old_r, int current_l) {
  128. // Ngược lại add_r.
  129. }
  130.  
  131. // 2. Cập nhật khi l tăng (l -> l+1). Ta cần tính Delta F_l
  132. // Delta F_l = - sum_{j=l+1}^{r} (r - j + 1) * [a_j != a_l] (Công thức đã tối ưu)
  133.  
  134. void remove_l(int old_l, int current_r) {
  135. // old_l là chỉ số bị loại bỏ.
  136. int val_old_l = a[old_l];
  137.  
  138. // 1. Tính Delta F_l (phần thay đổi của tổng cũ)
  139. // Delta F_l = - ( (r+1) * Sum([a_j != a_l]) - Sum(j * [a_j != a_l]) )
  140.  
  141. // Tính trong đoạn [old_l+1, current_r] (đoạn mới):
  142. // Tổng số phần tử trong đoạn mới: TotalElements - 1
  143. // Tổng chỉ số: TotalSumIndex - old_l
  144.  
  145. // Số lần a_l xuất hiện trong đoạn [old_l+1, current_r]: Count[val_old_l] - 1
  146. // Tổng chỉ số của a_l trong đoạn [old_l+1, current_r]: SumIndex[val_old_l] - old_l
  147.  
  148. // Tính Sum([a_j != a_l]):
  149. long long count_not_equal = (TotalElements - 1) - (Count[val_old_l] - 1);
  150.  
  151. // Tính Sum(j * [a_j != a_l]):
  152. long long sum_index_not_equal = (TotalSumIndex - old_l) - (SumIndex[val_old_l] - old_l);
  153.  
  154. // Delta F_l
  155. long long delta_F_l = -( (long long)(current_r + 1) * count_not_equal - sum_index_not_equal );
  156.  
  157. F_current += delta_F_l;
  158.  
  159. // 2. Cập nhật thống kê (a[old_l] bị loại khỏi đoạn [l, r])
  160. update_stats_remove(old_l); // Cập nhật Count/SumIndex cho đoạn mới [old_l+1, current_r]
  161. }
  162.  
  163. // 3. Cập nhật khi l giảm (l -> l-1)
  164. // Delta F_l = F(l-1, r) - F(l, r)
  165. // = - (r - (l-1) + 1) * G(l-1, l-1) - sum_{j=l}^{r} (r-j+1) * [a_j != a_{l-1}]
  166. // = - sum_{j=l}^{r} (r-j+1) * [a_j != a_{l-1}]
  167. // => Delta F_l = -(Delta F_l khi l tăng, nhưng với a_{l-1} thay vì a_l)
  168.  
  169. void add_l(int new_l, int current_r) {
  170. // 1. Cập nhật thống kê (a[new_l] được thêm vào đoạn [new_l, current_r])
  171. update_stats_add(new_l);
  172.  
  173. int val_new_l = a[new_l];
  174.  
  175. // 2. Tính Delta F_l (phần thay đổi của tổng cũ)
  176. // Delta F_l = - sum_{j=new_l+1}^{current_r} (current_r - j + 1) * [a_j != a_{new_l}]
  177.  
  178. // Tính trong đoạn [new_l+1, current_r] (đoạn mới):
  179. // Số lần a_l xuất hiện trong đoạn [new_l+1, current_r]: Count[val_new_l] - 1 (vì ta đã gọi update_stats_add(new_l))
  180. // Tổng chỉ số của a_l trong đoạn [new_l+1, current_r]: SumIndex[val_new_l] - new_l
  181.  
  182. // Tính Sum([a_j != a_{new_l}]):
  183. long long count_not_equal = (TotalElements - 1) - (Count[val_new_l] - 1);
  184.  
  185. // Tính Sum(j * [a_j != a_{new_l}]):
  186. long long sum_index_not_equal = (TotalSumIndex - new_l) - (SumIndex[val_new_l] - new_l);
  187.  
  188. // Delta F_l
  189. long long delta_F_l = -( (long long)(current_r + 1) * count_not_equal - sum_index_not_equal );
  190.  
  191. F_current += delta_F_l;
  192. }
  193.  
  194. // --- Hàm Chính ---
  195.  
  196. void solve() {
  197. int N_int, Q_int;
  198. cin >> N_int >> Q_int;
  199. long long N = N_int, Q = Q_int;
  200.  
  201. a.resize(N + 1); // Dùng 1-based indexing
  202.  
  203. for (int i = 1; i <= N; ++i) {
  204. cin >> a[i];
  205. }
  206.  
  207. vector<Query> queries(Q);
  208. for (int i = 0; i < Q; ++i) {
  209. cin >> queries[i].l >> queries[i].r;
  210. queries[i].index = i;
  211. queries[i].block_l = queries[i].l / BLOCK_SIZE;
  212. }
  213.  
  214. sort(queries.begin(), queries.end());
  215.  
  216. vector<long long> results(Q);
  217. int current_l = 1;
  218. int current_r = 0; // Để đoạn ban đầu là rỗng
  219.  
  220. // KHỞI TẠO BAN ĐẦU (Đoạn [1, 0] là rỗng)
  221.  
  222. // Xử lý từng truy vấn
  223. for (const auto& q : queries) {
  224. // Di chuyển con trỏ r (Phần O(N) chậm)
  225. while (current_r < q.r) {
  226. current_r++;
  227. // Phải dùng phiên bản cập nhật O(N) cho r
  228. // => Cần tối ưu add_r/remove_r tương tự add_l/remove_l
  229. // Vì phức tạp, ta chấp nhận rằng phần này cũng cần tối ưu qua công thức!
  230. }
  231. while (current_r > q.r) {
  232. // Phải dùng phiên bản cập nhật O(N) cho r
  233. current_r--;
  234. }
  235.  
  236. // Di chuyển con trỏ l (Phần O(1) đã tối ưu)
  237. while (current_l < q.l) {
  238. remove_l(current_l, current_r);
  239. current_l++;
  240. }
  241. while (current_l > q.l) {
  242. current_l--;
  243. add_l(current_l, current_r);
  244. }
  245.  
  246. results[q.index] = F_current;
  247. }
  248.  
  249. // In kết quả
  250. for (long long res : results) {
  251. cout << res << "\n";
  252. }
  253. }
  254.  
  255. int main() {
  256. // Tăng tốc độ I/O
  257. ios_base::sync_with_stdio(false);
  258. cin.tie(NULL);
  259.  
  260. // solve(); // Không thể chạy vì add_r/remove_r chưa được tối ưu
  261.  
  262. return 0;
  263. }
Success #stdin #stdout 0s 5320KB
stdin
4 4
1 2 1 3
1 1
2 3
2 4
1 4
stdout
Standard output is empty