【AtCoder】ABC 442 D - Swap and Range Sum
AtCoder/ABC/D問題AtCoder/ABC/400点問題AtCoder/灰DiffAtCoder/NoviSteps/2QAtCoder/クエリ処理問題AtCoder/累積和AtCoder/データ構造/Segment Tree競技プログラミング

D - Swap and Range Sum
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
AtCoder
実行時間制限: 2 sec / メモリ制限: 1024 MiB / Difficulty: 293 / NoviSteps: 2Q / 配点: 400 点
問題概要
長さ の数列 が与えられる。
個のクエリが与えられるので、順に処理せよ。 各クエリは以下のいずれかの形式である。
1 x: と の値を入れ替える。2 l r: の値を求める。
制約
- 種類目のクエリについて、
- 種類目のクエリについて、
- 入力は全て整数
考察
素直に考える
クエリ2に注目すると、任意の区間和を高速に求める必要がある。 これは累積和を用いることで前計算 、各クエリに対して 時間で答えることができる。
問題はクエリ1だが、ここで値を交換する隣接2項以外の累積和は変化しないことに注目する。
累積和配列を としたとき、 までは値が変化しないのは当然として、 の値が不変なことから、 以降も値が変化しないことがわかる。
よって、 と をswapした後、
と更新すればよい。
上位のデータ構造で殴る
慣れている人は、このクエリの形式を見た時点で、とあるデータ構造が思い浮かぶかもしれない。
クエリ1では「区間の1点更新を2回行う」、クエリ2では「任意の区間和を求める」という操作を行っている。
このような操作を高速に行うデータ構造として、Segment Tree や BIT(Fenwick Tree) があるので、これらを用いることで簡単に実装することができる。
実装例
考察1
CPP
1.#include <bits/stdc++.h>2.using namespace std;3. 4.#define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++)5. 6.using ll = long long;7. 8.// ======================================== //9. 10.int main()11.{12. int N, Q;13. cin >> N >> Q;14. vector<int> A(N);15. rep(i, 0, N) cin >> A[i];16. 17. vector<ll> ps(N + 1, 0);18. rep(i, 0, N) ps[i + 1] = ps[i] + A[i];19. 20. while (Q--)21. {22. int t;23. cin >> t;24. 25. if (t == 1)26. {27. int x;28. cin >> x;29. x--;30. 31. swap(A[x], A[x + 1]);32. ps[x + 1] = ps[x] + A[x];33. }34. else35. {36. int l, r;37. cin >> l >> r;38. l--;39. 40. cout << ps[r] - ps[l] << endl;41. }42. }43. 44. return 0;45.}
Submission #72769528 - JPRS Programming Contest 2026#1 (AtCoder Beginner Contest 442)
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
AtCoder
考察2
実装例ではACLのSegtreeを用いている。
CPP
1.#include <bits/stdc++.h>2.using namespace std;3. 4.#if __has_include(<atcoder/all>)5.#include <atcoder/all>6.using namespace atcoder;7.#endif8. 9.#define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++)10. 11.using ll = long long;12. 13.// ======================================== //14. 15.ll op(ll a, ll b)16.{17. return a + b;18.}19. 20.ll e()21.{22. return 0LL;23.}24. 25.int main()26.{27. int N, Q;28. cin >> N >> Q;29. vector<ll> A(N);30. rep(i, 0, N) cin >> A[i];31. 32. segtree<ll, op, e> seg(A);33. 34. while (Q--)35. {36. int t;37. cin >> t;38. 39. if (t == 1)40. {41. int x;42. cin >> x;43. x--;44. 45. ll a = seg.get(x);46. ll b = seg.get(x + 1);47. seg.set(x, b);48. seg.set(x + 1, a);49. }50. else if (t == 2)51. {52. int l, r;53. cin >> l >> r;54. 55. cout << seg.prod(l - 1, r) << endl;56. }57. }58. 59. return 0;60.}
Submission #72697399 - JPRS Programming Contest 2026#1 (AtCoder Beginner Contest 442)
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
AtCoder
実装時間: 10 分
コメント
「セグ木で殴る」というのはこういうことか。





