#pragma GCC target("avx2") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") #include #include #include #include #include template struct SegmentTree { int n; std::vector data; T e; SegmentTree(int n, T e) : e(e) { int n2 = 1; while (n2 < n) { n2 *= 2; } this->n = n2; this->data = std::vector(n2 * 2, e); } void build() { for (int i = this->n - 1; i >= 1; i--) { this->data[i] = this->data[i * 2] + this->data[i * 2 + 1]; } } void update(int i, T x) { int k = i + this->n; this->data[k] = x; while (k > 1) { k /= 2; this->data[k] = this->data[k * 2] + this->data[k * 2 + 1]; } } auto query(int l, int r, U ls, U rs) { l += this->n; r += this->n; while (l < r) { if (l & 1) { ls = ls + this->data[l]; l++; } if (r & 1) { r--; rs = this->data[r] + rs; } l /= 2; r /= 2; } return ls + rs; } }; using int64 = std::int64_t; constexpr int64 MOD = 998244353; struct Vec { std::array data; Vec() { std::fill_n(this->data.begin(), 6, 0); } Vec(const int (&a)[6]) { std::copy_n(a, 6, this->data.begin()); } }; struct Matrix { std::array, 6> data; Matrix() { std::fill_n(this->data.begin(), 6, std::array()); for (int i = 0; i < 6; i++) { std::fill_n(this->data[i].begin(), i + 1, 0); } } Matrix(const int (&a)[6][6]) { for (int i = 0; i < 6; i++) { std::copy_n(a[i], i + 1, this->data[i].begin()); } } }; Matrix operator+(const Matrix &a, const Matrix &b) { Matrix result; for (int i = 0; i < 6; i++) { for (int j = 0; j <= i; j++) { for (int k = j; k <= i; k++) { result.data[i][j] += a.data[i][k] * b.data[k][j]; } result.data[i][j] %= MOD; } } return result; } Vec operator+(const Vec &a, const Matrix &b) { Vec result; for (int i = 0; i < 6; i++) { for (int j = 0; j <= i; j++) { result.data[j] += a.data[i] * b.data[i][j]; } } for (int i = 0; i < 6; i++) { result.data[i] %= MOD; } return result; } Vec operator+(const Matrix &a, const Vec &b) { Vec result; for (int i = 0; i < 6; i++) { for (int j = 0; j <= i; j++) { result.data[i] += a.data[i][j] * b.data[j]; } } for (int i = 0; i < 6; i++) { result.data[i] %= MOD; } return result; } int64 operator+(const Vec &a, const Vec &b) { int64 result = 0; for (int i = 0; i < 6; i++) { result += a.data[i] * b.data[i]; } return result % MOD; } const std::array node = {{ Matrix({ {1, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0}, {1, 1, 1, 0, 0, 0}, {0, 0, 0, 1, 0, 0}, {0, 0, 0, 1, 1, 0}, {0, 0, 0, 1, 1, 1}, }), Matrix({ {1, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 0}, {1, 1, 0, 1, 0, 0}, {0, 0, 1, 0, 1, 0}, {0, 0, 1, 0, 1, 1}, }) }}; const Matrix identity = Matrix({ {1, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 0}, {0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 1}, }); int main() { int n, q; scanf("%d%d", &n, &q); std::vector s(n); for (int i = 0; i < n; i++) { char c; scanf(" %c", &c); s[i] = c - '0'; } SegmentTree st(n, identity); for (int i = 0; i < n; i++) { st.data[i + st.n] = node[s[i]]; } st.build(); for (int i = 0; i < q; i++) { int t; scanf("%d", &t); if (t == 1) { int j; scanf("%d", &j); j--; s[j] = 1 - s[j]; st.update(j, node[s[j]]); } else { int l, r; scanf("%d%d", &l, &r); l--; int64 ans = st.query(l, r, Vec({0, 0, 0, 0, 0, 1}), Vec({1, 0, 0, 0, 0, 0})); printf("%lld\n", ans); } } }