No.151 セグメントフィッシング
No.151 セグメントフィッシング - yukicoder
No.259 セグメントフィッシング+ - yukicoder
- 鏡面反転を配列を二倍にしてリング状に扱うことで解く問題。
- 鏡面反転のアイデアはすぐに思いついたが出力が半開区間なのでおかしな場合分けをしてなかなか実装ができなかった...。
- 単純に z をデクレメントして半開区間を閉区間にするだけで場合わけがいらなくなるというアレ...。
- 出力格納変数が int で overflow してしまっていた...。
- セグメントフィッシング+ の方もほぼ同じ。こっちは t が与えられるので B で割る必要がある。
class SegmentFishing { public: void solve(void) { int N,Q; cin>>N>>Q; int t = 0; int B = 2*N; // 配列に含まれる魚を移動するのではなくて,魚の格納インデックスが時間毎に // 変化すると考える。 // 長さ 2*N の配列を考えて N-1 -> N, 2*N -> 0 とリング上につながっていて、 // 0~N-1 が右向き、N~2*n-1 が左向きとみなすことで端の魚の向きの反転を表現できる。 // 区間の総和を計算するには BIT をつかえばよい。 BIT<ll> ring(B); // O(Q*log(N)) while (Q--) { char x; int y,z; cin>>x>>y>>z; switch (x) { case 'R': ring.add((y-t+B)%B, z); break; case 'L': ring.add((B-1-y-t+B)%B, z); break; case 'C': { ll cnt = 0; --z; // [y,z) -> [y,z-1] 閉区間で扱う for (int i = 0; i < 2; ++i) { int l,r; if (i == 0) { l = (y-t+B)%B; r = (z-t+B)%B; } else { r = (B-1-y-t+B)%B; l = (B-1-z-t+B)%B; } ll add = ring.sum(r) - ring.sum(l-1); // 配列の末尾をまたぐケース if (r < l) add += ring.sum(B-1); cnt += add; } cout<<cnt<<endl; } break; default: assert(false); break; } ++t; if (t > B) t-=B; } } };