結果
問題 |
No.2554 MMA文字列2 (Query Version)
|
ユーザー |
|
提出日時 | 2025-04-25 12:20:54 |
言語 | D (dmd 2.109.1) |
結果 |
AC
|
実行時間 | 1,230 ms / 5,000 ms |
コード長 | 5,879 bytes |
コンパイル時間 | 5,223 ms |
コンパイル使用メモリ | 208,616 KB |
実行使用メモリ | 74,548 KB |
最終ジャッジ日時 | 2025-04-25 12:21:52 |
合計ジャッジ時間 | 53,516 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 55 |
ソースコード
import std; void main () { int N = readln.chomp.to!int; string S = readln.chomp; int Q = readln.chomp.to!int; struct node { int[26] count; long[26] two_same; long[26] two_diff; long val; string toString () { return val.to!string; } } node op (node x, node y) { node res; int ysum = y.count[].sum; // MMAを完成させる // - 左側区間2文字 + 右側区間1文字 // - 左側区間1文字 + 右側区間2文字 res.val = x.val + y.val; foreach (i; 0 .. 26) { res.val += x.two_same[i] * (ysum - y.count[i]); res.val += x.count[i] * y.two_diff[i]; } foreach (i; 0 .. 26) { res.two_same[i] = x.two_same[i] + y.two_same[i] + 1L * x.count[i] * y.count[i]; res.two_diff[i] = x.two_diff[i] + y.two_diff[i] + 1L * x.count[i] * (ysum - y.count[i]); } foreach (i; 0 .. 26) { res.count[i] = x.count[i] + y.count[i]; } return res; } node e () { return node(); } auto seg = new SegmentTree!(node, op, e)(N); foreach (i; 0 .. N) { node v; v.count[S[i] - 'A']++; seg.set(i, v); } auto ans = new long[](0); foreach (i; 0 .. Q) { auto query = readln.split; int t = query[0].to!int; if (t == 1) { int x = query[1].to!int; char c = query[2].to!char; x--; node v; v.count[c - 'A']++; seg.set(x, v); } if (t == 2) { int l = query[1].to!int; int r = query[2].to!int; l--; ans ~= seg.prod(l, r).val; } } writefln("%(%s\n%)", ans); } import std.traits : ReturnType, isCallable, Parameters; import std.meta : AliasSeq; class SegmentTree (T, alias ope, alias e) if ( isCallable!(ope) && isCallable!(e) && is (ReturnType!(ope) == T) && is (ReturnType!(e) == T) && is (Parameters!(ope) == AliasSeq!(T, T)) && is (Parameters!(e) == AliasSeq!()) ) { /* 内部の配列が1-indexedで2冪のセグメントツリー */ import std.format : format; T[] X; size_t length; /* --- Constructors --- */ this (size_t length_) { adjust_array_length(length_); for (size_t i = length; i < 2*length; i++) { X[i] = e(); } build(); } import std.range.primitives : isInputRange; this (R) (R Range) if (isInputRange!(R) && is (ElementType!(R) == T)) { adjust_array_length(walkLength(Range)); size_t i = length; foreach (item; Range) { X[i] = item; i++; } while (i < 2*length) { X[i] = e(); i++; } build(); } /* --- Functions --- */ private void adjust_array_length (size_t length_) { length = 1; while (length <= length_) length *= 2; X = new T[](2*length); } void set_with_no_update (size_t idx, T val) in { assert(idx < length, format("In function \"set_with_no_update\", idx is out of range. (length = %s idx = %s)", length, idx)); } do { X[length+idx] = val; } void build () { for (size_t i = length-1; 1 <= i; i--) { X[i] = ope(X[2*i], X[2*i+1]); } } public override string toString () { string res = ""; int level = 1; while ((2^^(level-1)) < X.length) { res ~= format("level: %2s | ", level); for (size_t i = (2^^(level-1)); i < (2^^level); i++) { res ~= format("%s%s", X[i], (i == (2^^level)-1 ? "\n" : " ")); } level++; } return res; } void set (size_t idx, T val) in { assert(idx < length, format("In function \"set\", idx is out of range. (length = %s idx = %s)", length, idx)); } do { idx += length; X[idx] = val; while (2 <= idx) { idx /= 2; X[idx] = ope(X[2*idx], X[2*idx+1]); } } T get (size_t idx) in { assert(idx < length, format("In function \"get\", idx is out of range. (length = %s idx = %s)", length, idx)); } do { idx += length; return X[idx]; } T prod (size_t l, size_t r) in { assert(l < length, format("In function \"prod\", l is out of range. (length = %s l = %s)", length, l)); assert(r <= length, format("In function \"prod\", r is out of range. (length = %s r = %s)", length, r)); assert(l <= r, format("In function \"prod\", l < r must be satisfied. (length = %s l = %s, r = %s)", length, l, r)); } do { /* Returns all prod O(1) */ if (l == 0 && r == length) return X[1]; if (l == r) return e(); /* Closed interval [l, r] */ r--; l += length, r += length; T LeftProd, RightProd; LeftProd = RightProd = e(); while (l <= r) { if (l % 2 == 1) { LeftProd = ope(LeftProd, X[l]); l++; } if (r % 2 == 0) { RightProd = ope(X[r], RightProd); r--; } l /= 2; r /= 2; } return ope(LeftProd, RightProd); } }