「ZJOI2017」树状数组 题解
前言
UOJ 上有很强的数据。
题意简述
yzh 做 OI 题维护序列
她实现了一个后缀和查询函数
初始
现在,你需要对每一个查询,求出她错误的实现依然能够得到正确答案的概率,对
题目分析
初步分析
肯定要分析
。
此时 。注意到在模 意义下,右侧为 。左侧就是到目前位置我们进行了多少次操作,这个随便维护。我们就把问题具象化成求某一个位置为 的概率。 。问题简化成求两个位置值相等的概率。
暴力模拟
我们考虑一个
对于第一个问题(求
不怎么有用的发现
事实上,我们只维护
对于第二个问题,我们想当然地求出
我们发现,有些操作对
namespace $pts50 { pair<int, int> Q[N]; void modify(int l, int r) { Q[++X] = { l, r }; } mint query(int l, int r) { if (l > 1) { --l; mint a[2][2] = { { 1, 0 }, { 0, 0 } }; for (int i = 1; i <= X; ++i) { mint t[2][2] = {{ a[0][0], a[0][1] }, { a[1][0], a[1][1] }}; mint p = inv[Q[i].second - Q[i].first + 1]; if (Q[i].first <= l && r <= Q[i].second) { for (int x : { 0, 1 }) for (int y : { 0, 1 }) a[x][y] = t[!x][y] * p + t[x][!y] * p + t[x][y] * (1 - p * 2); } else if (Q[i].first <= l && l <= Q[i].second) { for (int o : { 0, 1 }) { a[0][o] = t[0][o] * (1 - p) + t[1][o] * p; a[1][o] = t[1][o] * (1 - p) + t[0][o] * p; } } else if (Q[i].first <= r && r <= Q[i].second) { for (int o : { 0, 1 }) { a[o][0] = t[o][0] * (1 - p) + t[o][1] * p; a[o][1] = t[o][1] * (1 - p) + t[o][0] * p; } } } return a[0][0] + a[1][1]; } else { mint a[] = { 1, 0 }; for (int i = 1; i <= X; ++i) if (Q[i].first <= r && r <= Q[i].second) { mint p = inv[Q[i].second - Q[i].first + 1]; mint t[] = { a[0], a[1] }; a[0] = t[0] * (1 - p) + t[1] * p; a[1] = t[1] * (1 - p) + t[0] * p; } return a[X & 1]; } } void solve() { for (int op, l, r, i = 1; i <= m; ++i) { scanf("%d%d%d", &op, &l, &r); if (op == 1) { modify(l, r); } else { printf("%d\n", query(l, r).raw()); } } } }
抽丝剥茧,转化为熟悉的模型
问题都分析到这了,矩阵呼之欲出了。各种数据结构在你脑海里的形象愈发清晰。
问题一
先来看看好下手的问题一。我们把
然后,我们请出一个能够区间乘矩阵,单点查询的数据结构。线段树是也。
于是,我们在线地解决了问题一,修改 / 询问
问题二
类似的,我们把
- 完全包含
- 仅包含左端点
- 仅包含右端点
但是,这时候,我们发现有了区间包含关系的限制,十分地不好搞。
发现如果拍到一个二维笛卡尔坐标系上,这是二维数点状物。俗话说得好,二维数点,静态扫描线而动态 CDQ 也。这里我们使用 CDQ 分治就能解决问题。
三维偏序,一维时间,时间轴分治解决;再一维双指针维护解决;最后一维,数据结构解决。
我们先递归解决
这里我们先递归了
考虑完全包含、包含左端点两种情况,包含右端点类似。
我们先分别把
考虑以此枚举
上图中,中间灰色的线表示分治中心,右侧黑色的竖线表示我们枚举的
- 红色:这一类右端点已经小于
的左端点,没有用处,忽略。 - 蓝色:这一类右端点大于等于
的右端点,是完全包含类型。 - 绿色:这一类右端点小于
的右端点,仅包含 的左端点。
所以我们情不自禁使用两个数据结构,分别维护两种转移矩阵。查询的时候,按照需要查询即可。这个数据结构需要支持单点修改,区间查询矩阵乘。动态开点线段树即可。
于是,我们离线地解决了问题二。时间复杂度不难分析出为
收尾工作(卡常)
整体空间复杂度很不错,差不多是线性的
整体时间复杂度在两只
我们发现,由于我们提到修改的顺序不影响答案,那么我们把处理右端点提出来,做两次 CDQ 分治,这样,每次分治内部不需要排序,而是使用原地归并。将
我们再次发现,在处理完全包含类型时,我们的区间查询是后缀查询,那么用一棵树状数组代替一棵线段树,时间复杂度没有变化,但是常数更小了。由于我不会动态开点树状数组这种科技,所以采用了时间戳清空。
我们又又发现,线段树可以搞一搞。我们多维护一个 bool
类型的标记,表示这个节点的矩阵是不是单位矩阵,在询问时,如果遇到一个单位矩阵,就不进行矩阵乘法。在新建节点时,我们采用直接赋值,而不是先弄成单位矩阵,再做一次矩阵乘法。
我们努努力,把矩阵乘法手动做循环展开。
我们上传统手艺,加上超级快读快写。
我们发现,我们终于过了这题……
代码
原味代码( 行)
#pragma GCC optimize("Ofast", "inline", "fast-math") #include <cstdio> #include <iostream> #include <limits> #include <cassert> #include <cstring> #include <algorithm> using namespace std; namespace Mod_Int_Class { template <typename T, typename _Tp> constexpr bool in_range(_Tp val) { return std::numeric_limits<T>::min() <= val && val <= std::numeric_limits<T>::max(); } template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value>> static constexpr inline bool is_prime(_Tp val) { if (val < 2) return false; for (_Tp i = 2; i * i <= val; ++i) if (val % i == 0) return false; return true; } template <auto _mod = 998244353, typename T = int, typename S = long long> class Mod_Int { static_assert(in_range<T>(_mod), "mod must in the range of type T."); static_assert(std::is_integral<T>::value, "type T must be an integer."); static_assert(std::is_integral<S>::value, "type S must be an integer."); public: constexpr Mod_Int() noexcept = default; template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value>> constexpr Mod_Int(_Tp v) noexcept: val(0) { if (0 <= S(v) && S(v) < mod) val = v; else val = (S(v) % mod + mod) % mod; } constexpr T const& raw() const { return this -> val; } static constexpr T mod = _mod; template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value>> constexpr friend Mod_Int pow(Mod_Int a, _Tp p) { return a ^ p; } constexpr friend Mod_Int sub(Mod_Int a, Mod_Int b) { return a - b; } constexpr friend Mod_Int& tosub(Mod_Int& a, Mod_Int b) { return a -= b; } constexpr friend Mod_Int add(Mod_Int a) { return a; } template <typename... args_t> constexpr friend Mod_Int add(Mod_Int a, args_t... args) { return a + add(args...); } constexpr friend Mod_Int mul(Mod_Int a) { return a; } template <typename... args_t> constexpr friend Mod_Int mul(Mod_Int a, args_t... args) { return a * mul(args...); } template <typename... args_t> constexpr friend Mod_Int& toadd(Mod_Int& a, args_t... b) { return a = add(a, b...); } template <typename... args_t> constexpr friend Mod_Int& tomul(Mod_Int& a, args_t... b) { return a = mul(a, b...); } template <T __mod = mod, typename = std::enable_if_t<is_prime(__mod)>> static constexpr inline T inv(T a) { assert(a != 0); return _pow(a, mod - 2); } constexpr Mod_Int& operator + () const { return *this; } constexpr Mod_Int operator - () const { return _sub(0, val); } constexpr Mod_Int inv() const { return inv(val); } constexpr friend inline Mod_Int operator + (Mod_Int a, Mod_Int b) { return _add(a.val, b.val); } constexpr friend inline Mod_Int operator - (Mod_Int a, Mod_Int b) { return _sub(a.val, b.val); } constexpr friend inline Mod_Int operator * (Mod_Int a, Mod_Int b) { return _mul(a.val, b.val); } constexpr friend inline Mod_Int operator / (Mod_Int a, Mod_Int b) { return _mul(a.val, inv(b.val)); } template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value>> constexpr friend inline Mod_Int operator ^ (Mod_Int a, _Tp p) { return _pow(a.val, p); } constexpr friend inline Mod_Int& operator += (Mod_Int& a, Mod_Int b) { return a = _add(a.val, b.val); } constexpr friend inline Mod_Int& operator -= (Mod_Int& a, Mod_Int b) { return a = _sub(a.val, b.val); } constexpr friend inline Mod_Int& operator *= (Mod_Int& a, Mod_Int b) { return a = _mul(a.val, b.val); } constexpr friend inline Mod_Int& operator /= (Mod_Int& a, Mod_Int b) { return a = _mul(a.val, inv(b.val)); } template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value>> constexpr friend inline Mod_Int& operator ^= (Mod_Int& a, _Tp p) { return a = _pow(a.val, p); } constexpr friend inline bool operator == (Mod_Int a, Mod_Int b) { return a.val == b.val; } constexpr friend inline bool operator != (Mod_Int a, Mod_Int b) { return a.val != b.val; } constexpr Mod_Int& operator ++ () { this -> val + 1 == mod ? this -> val = 0 : ++this -> val; return *this; } constexpr Mod_Int& operator -- () { this -> val == 0 ? this -> val = mod - 1 : --this -> val; return *this; } constexpr Mod_Int operator ++ (int) { Mod_Int res = *this; this -> val + 1 == mod ? this -> val = 0 : ++this -> val; return res; } constexpr Mod_Int operator -- (int) { Mod_Int res = *this; this -> val == 0 ? this -> val = mod - 1 : --this -> val; return res; } friend std::istream& operator >> (std::istream& is, Mod_Int<mod, T, S>& x) { T ipt; return is >> ipt, x = ipt, is; } friend std::ostream& operator << (std::ostream& os, Mod_Int<mod, T, S> x) { return os << x.val; } protected: T val; static constexpr inline T _add(T a, T b) { return a >= mod - b ? a + b - mod : a + b; } static constexpr inline T _sub(T a, T b) { return a < b ? a - b + mod : a - b; } static constexpr inline T _mul(T a, T b) { return static_cast<S>(a) * b % mod; } template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value>> static constexpr inline T _pow(T a, _Tp p) { T res = 1; for (; p; p >>= 1, a = _mul(a, a)) if (p & 1) res = _mul(res, a); return res; } }; using mint = Mod_Int<>; using mod_t = mint; constexpr mint operator ""_m (unsigned long long x) { return mint(x); } constexpr mint operator ""_mod (unsigned long long x) { return mint(x); } } using namespace Mod_Int_Class; namespace FASTIO { const int MAX = 1 << 26; char buf[MAX], *ip = buf, obuf[MAX], *op = obuf; #define putchar(x) *FASTIO::op++ = x template <typename T> inline void read(T &x) { x = 0; char ch = *ip++; for (; ch < 48; ch = *ip++); for (; ch >= 48; ch = *ip++) x = (x << 3) + (x << 1) + (ch ^ 48); } template <typename T> inline void write(T x) { static short stack[20], top(0); do stack[++top] = x % 10; while (x /= 10); while (top) putchar(stack[top--] | 48); } } char MST; const int N = 100010; int n, m, X; mint inv[N]; #if false namespace $pts50 { pair<int, int> Q[N]; void modify(int l, int r) { Q[++X] = { l, r }; } mint query(int l, int r) { if (l > 1) { --l; mint a[2][2] = { { 1, 0 }, { 0, 0 } }; for (int i = 1; i <= X; ++i) { mint t[2][2] = {{ a[0][0], a[0][1] }, { a[1][0], a[1][1] }}; mint p = inv[Q[i].second - Q[i].first + 1]; if (Q[i].first <= l && r <= Q[i].second) { for (int x : { 0, 1 }) for (int y : { 0, 1 }) a[x][y] = t[!x][y] * p + t[x][!y] * p + t[x][y] * (1 - p * 2); } else if (Q[i].first <= l && l <= Q[i].second) { for (int o : { 0, 1 }) { a[0][o] = t[0][o] * (1 - p) + t[1][o] * p; a[1][o] = t[1][o] * (1 - p) + t[0][o] * p; } } else if (Q[i].first <= r && r <= Q[i].second) { for (int o : { 0, 1 }) { a[o][0] = t[o][0] * (1 - p) + t[o][1] * p; a[o][1] = t[o][1] * (1 - p) + t[o][0] * p; } } } return a[0][0] + a[1][1]; } else { mint a[] = { 1, 0 }; for (int i = 1; i <= X; ++i) if (Q[i].first <= r && r <= Q[i].second) { mint p = inv[Q[i].second - Q[i].first + 1]; mint t[] = { a[0], a[1] }; a[0] = t[0] * (1 - p) + t[1] * p; a[1] = t[1] * (1 - p) + t[0] * p; } return a[X & 1]; } } void solve() { for (int op, l, r, i = 1; i <= m; ++i) { scanf("%d%d%d", &op, &l, &r); if (op == 1) { modify(l, r); } else { printf("%d\n", query(l, r).raw()); } } } } #endif namespace $no_DS { #if false template <size_t O> struct Matrix_O { mint a[O][O]; int n, m; void init(int _n, int _m) { n = _n, m = _m; memset(a, 0x00, sizeof(a)); } void unit() { assert(n == m); for (int i = 0; i < n; ++i) a[i][i] = 1; } mint * operator [] (int x) { return a[x]; } mint const * operator [] (int x) const { return a[x]; } friend Matrix_O operator * (const Matrix_O& a, const Matrix_O& b) { Matrix_O res; assert(a.m == b.n); res.init(a.n, b.m); for (int i = 0; i < a.n; ++i) for (int j = 0; j < b.m; ++j) for (int k = 0; k < a.m; ++k) res[i][j] += a[i][k] * b[k][j]; return res; } friend Matrix_O& operator *= (Matrix_O& a, const Matrix_O& b) { return a = a * b; } void output() { for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) fprintf(stderr, "%d ", a[i][j].raw()); fprintf(stderr, "\n"); } } }; #endif mint ans[N]; namespace sub1 { struct Matrix { mint a[4][4]; inline void init() { memset(a, 0x00, sizeof(a)); } inline void unit() { a[0][0] = 1; a[1][1] = 1; a[2][2] = 1; a[3][3] = 1; } mint * operator [] (int x) { return a[x]; } mint const * operator [] (int x) const { return a[x]; } friend Matrix operator * (const Matrix& a, const Matrix& b) { Matrix res; res[0][0] = a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0] + a[0][3] * b[3][0]; res[0][1] = a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1] + a[0][3] * b[3][1]; res[0][2] = a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2] + a[0][3] * b[3][2]; res[0][3] = a[0][0] * b[0][3] + a[0][1] * b[1][3] + a[0][2] * b[2][3] + a[0][3] * b[3][3]; res[1][0] = a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0] + a[1][3] * b[3][0]; res[1][1] = a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1] + a[1][3] * b[3][1]; res[1][2] = a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2] + a[1][3] * b[3][2]; res[1][3] = a[1][0] * b[0][3] + a[1][1] * b[1][3] + a[1][2] * b[2][3] + a[1][3] * b[3][3]; res[2][0] = a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0] + a[2][3] * b[3][0]; res[2][1] = a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1] + a[2][3] * b[3][1]; res[2][2] = a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2] + a[2][3] * b[3][2]; res[2][3] = a[2][0] * b[0][3] + a[2][1] * b[1][3] + a[2][2] * b[2][3] + a[2][3] * b[3][3]; res[3][0] = a[3][0] * b[0][0] + a[3][1] * b[1][0] + a[3][2] * b[2][0] + a[3][3] * b[3][0]; res[3][1] = a[3][0] * b[0][1] + a[3][1] * b[1][1] + a[3][2] * b[2][1] + a[3][3] * b[3][1]; res[3][2] = a[3][0] * b[0][2] + a[3][1] * b[1][2] + a[3][2] * b[2][2] + a[3][3] * b[3][2]; res[3][3] = a[3][0] * b[0][3] + a[3][1] * b[1][3] + a[3][2] * b[2][3] + a[3][3] * b[3][3]; return res; } friend Matrix& operator *= (Matrix& a, const Matrix& b) { return a = a * b; } }; // using Matrix = Matrix_O<4>; struct Segment_Tree { Matrix a[N << 1]; int ls[N << 1], rs[N << 1]; bool tag[N << 1]; int pcnt, rt; inline int newNode() { a[++pcnt].init(); a[pcnt].unit(); ls[pcnt] = rs[pcnt] = 0; tag[pcnt] = false; return pcnt; } void modify(int& idx, int trl, int trr, int p, const Matrix& x) { if (!idx) idx = newNode(); if (tag[idx]) a[idx] *= x; else a[idx] = x, tag[idx] = true; if (trl == trr) return; int mid = (trl + trr) >> 1; if (p <= mid) modify(ls[idx], trl, mid, p, x); else modify(rs[idx], mid + 1, trr, p, x); } inline void modify(int p, const Matrix& x) { modify(rt, 1, n, p, x); } inline void build() { pcnt = 0, rt = 0; // a[0].init(K, K), a[0].unit(); } void query(int idx, int trl, int trr, int l, int r, Matrix& x) { if (l <= trl && trr <= r) { if (tag[idx]) x *= a[idx]; return; } int mid = (trl + trr) >> 1; if (ls[idx] && l <= mid) query(ls[idx], trl, mid, l, r, x); if (rs[idx] && r > mid) query(rs[idx], mid + 1, trr, l, r, x); } inline Matrix query(int l, int r) { Matrix t; t.init(); t.unit(); if (rt) query(rt, 1, n, l, r, t); return t; } // Matrix a[N]; // int K; // void modify(int p, const Matrix& x) { // a[p] *= x; // } // void build(int k) { // K = k; // for (int i = 1; i <= n; ++i) // a[i].init(k, k), a[i].unit(); // } // Matrix query(int l, int r) { // Matrix res; // res.init(K, K), res.unit(); // for (int i = l; i <= r; ++i) // res *= a[i]; // return res; // } }; struct Bit_Tree { Matrix a[N]; int T[N], timer; inline void refresh(int x) { if (T[x] != timer) { T[x] = timer; a[x].init(); a[x].unit(); } } inline void modify(int p, const Matrix& x) { for (; p; p &= p - 1) if (T[p] == timer) a[p] *= x; else T[p] = timer, a[p] = x; // refresh(p), a[p] *= x; } inline void build() { ++timer; } inline Matrix querysuf(int p) const { Matrix t; t.init(); t.unit(); for (; p <= n; p += p & -p) if (T[p] == timer) t *= a[p]; return t; } }; struct Question { int idx, l, r, T; } q[N]; Matrix qv[N]; int qcnt; void init() { } inline void add1(int l, int r) { q[++qcnt] = { -1, l, r, 0 }; q[qcnt].T = qcnt; } inline void add2(int l, int r, int idx) { assert(l > 1); --l; q[++qcnt] = { idx, l, r, 0 }; q[qcnt].T = qcnt; qv[idx].init(); qv[idx].unit(); } Bit_Tree t1; Segment_Tree t2, t3; // inline int f(bool x, bool y) { // return x << 1 | y; // } void solve(int l, int r) { if (l == r) return; int mid = (l + r) >> 1; solve(l, mid), solve(mid + 1, r); // static auto f = [] (int x, int y) -> int { // return x << 1 | y; // }; // 完全包含和包含左端点 // sort(q + l, q + mid + 1, // [] (const Question& a, const Question& b) -> bool { // return a.l < b.l; // } // ); // sort(q + mid + 1, q + r + 1, // [] (const Question& a, const Question& b) -> bool { // return a.l < b.l; // } // ); t1.build(), t2.build(); for (int i = mid + 1, j = l; i <= r; ++i) { for (; j <= mid && q[j].l <= q[i].l; ++j) if (!~q[j].idx) { int x = q[j].r; mint p = inv[q[j].r - q[j].l + 1]; Matrix t; // 完全包含 t.init(); t[0b10][0b00] = p; t[0b01][0b00] = p; t[0b00][0b00] = 1 - p * 2; t[0b11][0b01] = p; t[0b00][0b01] = p; t[0b01][0b01] = 1 - p * 2; t[0b00][0b10] = p; t[0b11][0b10] = p; t[0b10][0b10] = 1 - p * 2; t[0b01][0b11] = p; t[0b10][0b11] = p; t[0b11][0b11] = 1 - p * 2; // for (bool x : { 0, 1 }) // for (bool y : { 0, 1 }) { // t[f(!x, y)][f(x, y)] += p; // t[f(x, !y)][f(x, y)] += p; // t[f(x, y)][f(x, y)] += 1 - p * 2; // } t1.modify(x, t); // 左端点 t.init(); t[0b00][0b00] = 1 - p; t[0b10][0b00] = p; t[0b10][0b10] = 1 - p; t[0b00][0b10] = p; t[0b01][0b01] = 1 - p; t[0b11][0b01] = p; t[0b11][0b11] = 1 - p; t[0b01][0b11] = p; // for (bool o : { 0, 1 }) { // t[f(0, o)][f(0, o)] += 1 - p; // t[f(1, o)][f(0, o)] += p; // t[f(1, o)][f(1, o)] += 1 - p; // t[f(0, o)][f(1, o)] += p; // } t2.modify(x, t); } if (~q[i].idx) { qv[q[i].idx] *= t1.querysuf(q[i].r); if (q[i].l <= q[i].r - 1) qv[q[i].idx] *= t2.query(q[i].l, q[i].r - 1); } } inplace_merge(q + l, q + mid + 1, q + r + 1, [] (const Question& a, const Question& b) -> bool { return a.l < b.l; } ); } void solve2(int l, int r) { if (l == r) return; int mid = (l + r) >> 1; solve2(l, mid), solve2(mid + 1, r); t3.build(); for (int i = r, j = mid; i >= mid + 1; --i) { for (; j >= l && q[j].r >= q[i].r; --j) if (!~q[j].idx) { int x = q[j].l; mint p = inv[q[j].r - q[j].l + 1]; Matrix t; t.init(); t[0b00][0b00] = 1 - p; t[0b01][0b00] = p; t[0b01][0b01] = 1 - p; t[0b00][0b01] = p; t[0b10][0b10] = 1 - p; t[0b11][0b10] = p; t[0b11][0b11] = 1 - p; t[0b10][0b11] = p; // for (bool o : { 0, 1 }) { // t[f(o, 0)][f(o, 0)] += 1 - p; // t[f(o, 1)][f(o, 0)] += p; // t[f(o, 1)][f(o, 1)] += 1 - p; // t[f(o, 0)][f(o, 1)] += p; // } t3.modify(x, t); } if (~q[i].idx) { if (q[i].l + 1 <= q[i].r) qv[q[i].idx] *= t3.query(q[i].l + 1, q[i].r); } } inplace_merge(q + l, q + mid + 1, q + r + 1, [] (const Question& a, const Question& b) -> bool { return a.r < b.r; } ); } void solve() { solve(1, qcnt); sort(q + 1, q + qcnt + 1, [] (const Question& a, const Question& b) -> bool { return a.T < b.T; }); solve2(1, qcnt); for (int l = 1; l <= qcnt; ++l) if (~q[l].idx) { Matrix t; t.init(); t[0][0] = 1; t *= qv[q[l].idx]; ans[q[l].idx] = t[0][0] + t[0][3]; } } } namespace sub2 { struct Matrix { mint a[2][2]; inline void init() { memset(a, 0x00, sizeof(a)); } inline void unit() { a[0][0] = 1; a[1][1] = 1; } mint * operator [] (int x) { return a[x]; } mint const * operator [] (int x) const { return a[x]; } friend Matrix operator * (const Matrix& a, const Matrix& b) { Matrix res; res[0][0] = a[0][0] * b[0][0] + a[0][1] * b[1][0]; res[0][1] = a[0][0] * b[0][1] + a[0][1] * b[1][1]; res[1][0] = a[1][0] * b[0][0] + a[1][1] * b[1][0]; res[1][1] = a[1][0] * b[0][1] + a[1][1] * b[1][1]; return res; } friend Matrix& operator *= (Matrix& a, const Matrix& b) { return a = a * b; } }; struct Segment_Tree { Matrix a[N << 1]; int ls[N << 1], rs[N << 1]; bool tag[N << 1]; int pcnt, rt; inline int newNode() { a[++pcnt].init(); a[pcnt].unit(); ls[pcnt] = rs[pcnt] = 0; tag[pcnt] = false; return pcnt; } void modify(int& idx, int trl, int trr, int l, int r, const Matrix& x) { if (!idx) idx = newNode(); if (l <= trl && trr <= r) { if (tag[idx]) a[idx] *= x; else a[idx] = x, tag[idx] = true; return; } int mid = (trl + trr) >> 1; if (l <= mid) modify(ls[idx], trl, mid, l, r, x); if (r > mid) modify(rs[idx], mid + 1, trr, l, r, x); } inline void modify(int l, int r, const Matrix& x) { modify(rt, 1, n, l, r, x); } inline void build() { pcnt = 0, rt = 0; } void query(int idx, int trl, int trr, int p, Matrix& x) { if (tag[idx]) x *= a[idx]; if (trl == trr) return; int mid = (trl + trr) >> 1; if (ls[idx] && p <= mid) query(ls[idx], trl, mid, p, x); else if (rs[idx] && p > mid) query(rs[idx], mid + 1, trr, p, x); } inline Matrix query(int p) { Matrix t; t.init(); t.unit(); if (rt) query(rt, 1, n, p, t); return t; } // Matrix a[N]; // int K; // void modify(int l, int r, const Matrix& x) { // for (int i = l; i <= r; ++i) // a[i] *= x; // } // void build(int k) { // K = k; // for (int i = 1; i <= n; ++i) // a[i].init(k, k), a[i].unit(); // } // Matrix query(int p) { // return a[p]; // } }; Segment_Tree yzh; int X; inline void init() { yzh.build(), X = 0; } void add1(int l, int r) { Matrix t; t.init(); mint p = inv[r - l + 1]; t[0][0] = 1 - p, t[0][1] = p; t[1][0] = p, t[1][1] = 1 - p; yzh.modify(l, r, t); ++X; } void add2(int x, int idx) { Matrix res = yzh.query(x); Matrix t; t.init(); t[0][0] = 1, t[0][1] = 0; t = t * res; ans[idx] = t[0][X & 1]; } void solve() { } } bool isQ[N]; void solve() { sub1::init(), sub2::init(); for (int op, l, r, i = 1; i <= m; ++i) { FASTIO::read(op); FASTIO::read(l), FASTIO::read(r); // scanf("%d%d%d", &op, &l, &r); if (op == 1) { sub1::add1(l, r); sub2::add1(l, r); } else { isQ[i] = true; if (l > 1) { sub1::add2(l, r, i); } else { sub2::add2(r, i); } } } sub1::solve(), sub2::solve(); for (int i = 1; i <= m; ++i) if (isQ[i]) FASTIO::write(ans[i].raw()), putchar('\n'); } } char MED; int main() { fprintf(stderr, "Memory: %.2lfMB\n", (&MED - &MST) / 1024. / 1024); // freopen("ex_bit2.in", "r", stdin); // freopen("yzh", "w", stdout); #ifndef XuYueming // freopen("bit.in", "r", stdin); // freopen("bit.out", "w", stdout); #endif fread(FASTIO::buf, 1, FASTIO::MAX, stdin); // scanf("%d%d", &n, &m); FASTIO::read(n), FASTIO::read(m); inv[1] = 1; for (int i = 2; i <= n; ++i) inv[i] = -(mint::mod / i) * inv[mint::mod % i], assert(inv[i] * i == 1); $no_DS::solve(); fwrite(FASTIO::obuf, 1, FASTIO::op - FASTIO::obuf, stdout); return 0; } /* 当 l > 1 时: 相当于查的时候查 [l - 1, r - 1] sum[r, n] - sum[l - 1, n] = sum[l, r] -sum[l-1, r-1] = sum[l, r] sum[l, r] + sum[l-1, r-1] = 0 a[l-1] + a[r] = 0 a[l-1] = a[r] 注意到,如果之前有一个东西横跨了 [l-1, r] // 设其概率 1/len = p // 设这次操作外 bl0=a[l-1][0], ... // 可以用操作后的 a 还原出来 // 1. 恰落在了 l-1 或 r,概率 p * 2 // ans += p * 2 * (bl1 * br0 + bl0 * br1) // 2. 落在了其他位置,概率 p * (len - 2) // ans += p * (len-2) * (bl0 * br0 + bl1 * br1) // 记 恰改变了一个位置 的概率为 p // 1. 恰改变了 l-1 或 r,概率 p // ans += p * (bl1 * br0 + bl0 * br1) // 2. 两者都没变,概率 1-p // ans += (1-p) * (bl0 * br0 + bl1 * br1) // a[i][0] = (1 - b0) * p + b0 * (1 - p) // a0 = p + b0 * (1 - p*2) 当 l = 1 时: sum[r, n] - 0 = sum[l, r] sum[r, n] = sum[l, r] sum[r+1, n] = sum[l, r-1] sum[r+1, n] = sum[1, r-1] 记整个数组做了 x 次加法 sum[1, n] = x sum[1, n] - sum[1, r-1] - a[r] = sum[1, r-1] sum[1, n] - a[r] = 2 * sum[1, r-1] = 0 a[r] = x 静态区间?矩阵维护是也。夫预知答案如何,需维护若干矩阵。其困难之处在于,当 l>1 的情况难以搞。 正解肯定需要 CDQ 时间轴,CDQ 分治解决 左端点,归并解决 右端点,数据结构 */
正常代码( 行,略去取模板子)
#pragma GCC optimize("Ofast", "inline", "fast-math") #include <cstdio> #include <iostream> #include <limits> #include <cassert> #include <cstring> #include <algorithm> using namespace std; using namespace Mod_Int_Class; char MST; namespace FASTIO { const int MAX = 1 << 26; char buf[MAX], *ip = buf, obuf[MAX], *op = obuf; #define putchar(x) *FASTIO::op++ = x template <typename T> inline void read(T &x) { x = 0; char ch = *ip++; for (; ch < 48; ch = *ip++); for (; ch >= 48; ch = *ip++) x = (x << 3) + (x << 1) + (ch ^ 48); } template <typename T> inline void write(T x) { static short stack[20], top(0); do stack[++top] = x % 10; while (x /= 10); while (top) putchar(stack[top--] | 48); } } namespace $yzh { const int N = 100010; int n, m, X; mint inv[N]; mint ans[N]; namespace sub1 { struct Matrix { mint a[4][4]; inline void init() { memset(a, 0x00, sizeof(a)); } inline void unit() { a[0][0] = 1; a[1][1] = 1; a[2][2] = 1; a[3][3] = 1; } mint * operator [] (int x) { return a[x]; } mint const * operator [] (int x) const { return a[x]; } friend Matrix operator * (const Matrix& a, const Matrix& b) { Matrix res; res[0][0] = a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0] + a[0][3] * b[3][0]; res[0][1] = a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1] + a[0][3] * b[3][1]; res[0][2] = a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2] + a[0][3] * b[3][2]; res[0][3] = a[0][0] * b[0][3] + a[0][1] * b[1][3] + a[0][2] * b[2][3] + a[0][3] * b[3][3]; res[1][0] = a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0] + a[1][3] * b[3][0]; res[1][1] = a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1] + a[1][3] * b[3][1]; res[1][2] = a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2] + a[1][3] * b[3][2]; res[1][3] = a[1][0] * b[0][3] + a[1][1] * b[1][3] + a[1][2] * b[2][3] + a[1][3] * b[3][3]; res[2][0] = a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0] + a[2][3] * b[3][0]; res[2][1] = a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1] + a[2][3] * b[3][1]; res[2][2] = a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2] + a[2][3] * b[3][2]; res[2][3] = a[2][0] * b[0][3] + a[2][1] * b[1][3] + a[2][2] * b[2][3] + a[2][3] * b[3][3]; res[3][0] = a[3][0] * b[0][0] + a[3][1] * b[1][0] + a[3][2] * b[2][0] + a[3][3] * b[3][0]; res[3][1] = a[3][0] * b[0][1] + a[3][1] * b[1][1] + a[3][2] * b[2][1] + a[3][3] * b[3][1]; res[3][2] = a[3][0] * b[0][2] + a[3][1] * b[1][2] + a[3][2] * b[2][2] + a[3][3] * b[3][2]; res[3][3] = a[3][0] * b[0][3] + a[3][1] * b[1][3] + a[3][2] * b[2][3] + a[3][3] * b[3][3]; return res; } friend Matrix& operator *= (Matrix& a, const Matrix& b) { return a = a * b; } }; struct Segment_Tree { Matrix a[N << 1]; int ls[N << 1], rs[N << 1]; bool tag[N << 1]; int pcnt, rt; inline int newNode() { a[++pcnt].init(); a[pcnt].unit(); ls[pcnt] = rs[pcnt] = 0; tag[pcnt] = false; return pcnt; } void modify(int& idx, int trl, int trr, int p, const Matrix& x) { if (!idx) idx = newNode(); if (tag[idx]) a[idx] *= x; else a[idx] = x, tag[idx] = true; if (trl == trr) return; int mid = (trl + trr) >> 1; if (p <= mid) modify(ls[idx], trl, mid, p, x); else modify(rs[idx], mid + 1, trr, p, x); } inline void modify(int p, const Matrix& x) { modify(rt, 1, n, p, x); } inline void build() { pcnt = 0, rt = 0; } void query(int idx, int trl, int trr, int l, int r, Matrix& x) { if (l <= trl && trr <= r) { if (tag[idx]) x *= a[idx]; return; } int mid = (trl + trr) >> 1; if (ls[idx] && l <= mid) query(ls[idx], trl, mid, l, r, x); if (rs[idx] && r > mid) query(rs[idx], mid + 1, trr, l, r, x); } inline Matrix query(int l, int r) { Matrix t; t.init(); t.unit(); if (rt) query(rt, 1, n, l, r, t); return t; } }; struct Bit_Tree { Matrix a[N]; int T[N], timer; inline void refresh(int x) { if (T[x] != timer) { T[x] = timer; a[x].init(); a[x].unit(); } } inline void modify(int p, const Matrix& x) { for (; p; p &= p - 1) if (T[p] == timer) a[p] *= x; else T[p] = timer, a[p] = x; } inline void build() { ++timer; } inline Matrix querysuf(int p) const { Matrix t; t.init(); t.unit(); for (; p <= n; p += p & -p) if (T[p] == timer) t *= a[p]; return t; } }; struct Question { int idx, l, r, T; } q[N]; Matrix qv[N]; int qcnt; void init() { } inline void add1(int l, int r) { q[++qcnt] = { -1, l, r, 0 }; q[qcnt].T = qcnt; } inline void add2(int l, int r, int idx) { assert(l > 1); --l; q[++qcnt] = { idx, l, r, 0 }; q[qcnt].T = qcnt; qv[idx].init(); qv[idx].unit(); } Bit_Tree t1; Segment_Tree t2, t3; void solve(int l, int r) { if (l == r) return; int mid = (l + r) >> 1; solve(l, mid), solve(mid + 1, r); t1.build(), t2.build(); for (int i = mid + 1, j = l; i <= r; ++i) { for (; j <= mid && q[j].l <= q[i].l; ++j) if (!~q[j].idx) { int x = q[j].r; mint p = inv[q[j].r - q[j].l + 1]; Matrix t; // 完全包含 t.init(); t[0b10][0b00] = p; t[0b01][0b00] = p; t[0b00][0b00] = 1 - p * 2; t[0b11][0b01] = p; t[0b00][0b01] = p; t[0b01][0b01] = 1 - p * 2; t[0b00][0b10] = p; t[0b11][0b10] = p; t[0b10][0b10] = 1 - p * 2; t[0b01][0b11] = p; t[0b10][0b11] = p; t[0b11][0b11] = 1 - p * 2; t1.modify(x, t); // 左端点 t.init(); t[0b00][0b00] = 1 - p; t[0b10][0b00] = p; t[0b10][0b10] = 1 - p; t[0b00][0b10] = p; t[0b01][0b01] = 1 - p; t[0b11][0b01] = p; t[0b11][0b11] = 1 - p; t[0b01][0b11] = p; t2.modify(x, t); } if (~q[i].idx) { qv[q[i].idx] *= t1.querysuf(q[i].r); if (q[i].l <= q[i].r - 1) qv[q[i].idx] *= t2.query(q[i].l, q[i].r - 1); } } inplace_merge(q + l, q + mid + 1, q + r + 1, [] (const Question& a, const Question& b) -> bool { return a.l < b.l; } ); } void solve2(int l, int r) { if (l == r) return; int mid = (l + r) >> 1; solve2(l, mid), solve2(mid + 1, r); t3.build(); for (int i = r, j = mid; i >= mid + 1; --i) { for (; j >= l && q[j].r >= q[i].r; --j) if (!~q[j].idx) { int x = q[j].l; mint p = inv[q[j].r - q[j].l + 1]; Matrix t; t.init(); t[0b00][0b00] = 1 - p; t[0b01][0b00] = p; t[0b01][0b01] = 1 - p; t[0b00][0b01] = p; t[0b10][0b10] = 1 - p; t[0b11][0b10] = p; t[0b11][0b11] = 1 - p; t[0b10][0b11] = p; t3.modify(x, t); } if (~q[i].idx) { if (q[i].l + 1 <= q[i].r) qv[q[i].idx] *= t3.query(q[i].l + 1, q[i].r); } } inplace_merge(q + l, q + mid + 1, q + r + 1, [] (const Question& a, const Question& b) -> bool { return a.r < b.r; } ); } void solve() { solve(1, qcnt); sort(q + 1, q + qcnt + 1, [] (const Question& a, const Question& b) -> bool { return a.T < b.T; }); solve2(1, qcnt); for (int l = 1; l <= qcnt; ++l) if (~q[l].idx) { Matrix t; t.init(); t[0][0] = 1; t *= qv[q[l].idx]; ans[q[l].idx] = t[0][0] + t[0][3]; } } } namespace sub2 { struct Matrix { mint a[2][2]; inline void init() { memset(a, 0x00, sizeof(a)); } inline void unit() { a[0][0] = 1; a[1][1] = 1; } mint * operator [] (int x) { return a[x]; } mint const * operator [] (int x) const { return a[x]; } friend Matrix operator * (const Matrix& a, const Matrix& b) { Matrix res; res[0][0] = a[0][0] * b[0][0] + a[0][1] * b[1][0]; res[0][1] = a[0][0] * b[0][1] + a[0][1] * b[1][1]; res[1][0] = a[1][0] * b[0][0] + a[1][1] * b[1][0]; res[1][1] = a[1][0] * b[0][1] + a[1][1] * b[1][1]; return res; } friend Matrix& operator *= (Matrix& a, const Matrix& b) { return a = a * b; } }; struct Segment_Tree { Matrix a[N << 1]; int ls[N << 1], rs[N << 1]; bool tag[N << 1]; int pcnt, rt; inline int newNode() { a[++pcnt].init(); a[pcnt].unit(); ls[pcnt] = rs[pcnt] = 0; tag[pcnt] = false; return pcnt; } void modify(int& idx, int trl, int trr, int l, int r, const Matrix& x) { if (!idx) idx = newNode(); if (l <= trl && trr <= r) { if (tag[idx]) a[idx] *= x; else a[idx] = x, tag[idx] = true; return; } int mid = (trl + trr) >> 1; if (l <= mid) modify(ls[idx], trl, mid, l, r, x); if (r > mid) modify(rs[idx], mid + 1, trr, l, r, x); } inline void modify(int l, int r, const Matrix& x) { modify(rt, 1, n, l, r, x); } inline void build() { pcnt = 0, rt = 0; } void query(int idx, int trl, int trr, int p, Matrix& x) { if (tag[idx]) x *= a[idx]; if (trl == trr) return; int mid = (trl + trr) >> 1; if (ls[idx] && p <= mid) query(ls[idx], trl, mid, p, x); else if (rs[idx] && p > mid) query(rs[idx], mid + 1, trr, p, x); } inline Matrix query(int p) { Matrix t; t.init(); t.unit(); if (rt) query(rt, 1, n, p, t); return t; } }; Segment_Tree yzh; int X; inline void init() { yzh.build(), X = 0; } void add1(int l, int r) { Matrix t; t.init(); mint p = inv[r - l + 1]; t[0][0] = 1 - p, t[0][1] = p; t[1][0] = p, t[1][1] = 1 - p; yzh.modify(l, r, t); ++X; } void add2(int x, int idx) { Matrix res = yzh.query(x); Matrix t; t.init(); t[0][0] = 1, t[0][1] = 0; t = t * res; ans[idx] = t[0][X & 1]; } void solve() { } } bool isQ[N]; void solve() { FASTIO::read(n), FASTIO::read(m); inv[1] = 1; for (int i = 2; i <= n; ++i) inv[i] = -(mint::mod / i) * inv[mint::mod % i], assert(inv[i] * i == 1); sub1::init(), sub2::init(); for (int op, l, r, i = 1; i <= m; ++i) { FASTIO::read(op); FASTIO::read(l), FASTIO::read(r); if (op == 1) { sub1::add1(l, r); sub2::add1(l, r); } else { isQ[i] = true; if (l > 1) { sub1::add2(l, r, i); } else { sub2::add2(r, i); } } } sub1::solve(), sub2::solve(); for (int i = 1; i <= m; ++i) if (isQ[i]) FASTIO::write(ans[i].raw()), putchar('\n'); } } char MED; int main() { fprintf(stderr, "Memory: %.2lfMB\n", (&MED - &MST) / 1024. / 1024); #ifndef XuYueming // freopen("bit.in", "r", stdin); // freopen("bit.out", "w", stdout); #endif fread(FASTIO::buf, 1, FASTIO::MAX, stdin); $yzh::solve(); fwrite(FASTIO::obuf, 1, FASTIO::op - FASTIO::obuf, stdout); return 0; }
谁说我代码太长了?
#include<bits/stdc++.h> using namespace std;namespace Mod_Int_Class{template<typename T,typename _Tp>constexpr bool in_range(_Tp val){return std::numeric_limits<T>::min()<=val&&val<=std::numeric_limits<T>::max();}template<typename _Tp,typename=std::enable_if_t<std::is_integral<_Tp>::value>>static constexpr inline bool is_prime(_Tp val){if(val<2)return false;for(_Tp i=2;i*i<=val;++i)if(val%i==0)return false;return true;}template<auto _mod=998244353,typename T=int,typename S=long long>class Mod_Int{static_assert(in_range<T>(_mod),"mod must in the range of type T.");static_assert(std::is_integral<T>::value,"type T must be an integer.");static_assert(std::is_integral<S>::value,"type S must be an integer.");public:constexpr Mod_Int()noexcept=default;template<typename _Tp,typename=std::enable_if_t<std::is_integral<_Tp>::value>>constexpr Mod_Int(_Tp v)noexcept:val(0){if(0<=S(v)&&S(v)<mod)val=v;else val=(S(v)%mod+mod)%mod;}constexpr T const&raw()const{return this->val;}static constexpr T mod=_mod;template<typename _Tp,typename=std::enable_if_t<std::is_integral<_Tp>::value>>constexpr friend Mod_Int pow(Mod_Int a,_Tp p){return a^p;}constexpr friend Mod_Int sub(Mod_Int a,Mod_Int b){return a-b;}constexpr friend Mod_Int&tosub(Mod_Int&a,Mod_Int b){return a-=b;}constexpr friend Mod_Int add(Mod_Int a){return a;}template<typename...args_t>constexpr friend Mod_Int add(Mod_Int a,args_t...args){return a+add(args...);}constexpr friend Mod_Int mul(Mod_Int a){return a;}template<typename...args_t>constexpr friend Mod_Int mul(Mod_Int a,args_t...args){return a*mul(args...);}template<typename...args_t>constexpr friend Mod_Int&toadd(Mod_Int&a,args_t...b){return a=add(a,b...);}template<typename...args_t>constexpr friend Mod_Int&tomul(Mod_Int&a,args_t...b){return a=mul(a,b...);}template<T __mod=mod,typename=std::enable_if_t<is_prime(__mod)>>static constexpr inline T inv(T a){assert(a!=0);return _pow(a,mod-2);}constexpr Mod_Int&operator+()const{return*this;}constexpr Mod_Int operator-()const{return _sub(0,val);}constexpr Mod_Int inv()const{return inv(val);}constexpr friend inline Mod_Int operator+(Mod_Int a,Mod_Int b){return _add(a.val,b.val);}constexpr friend inline Mod_Int operator-(Mod_Int a,Mod_Int b){return _sub(a.val,b.val);}constexpr friend inline Mod_Int operator*(Mod_Int a,Mod_Int b){return _mul(a.val,b.val);}constexpr friend inline Mod_Int operator/(Mod_Int a,Mod_Int b){return _mul(a.val,inv(b.val));}template<typename _Tp,typename=std::enable_if_t<std::is_integral<_Tp>::value>>constexpr friend inline Mod_Int operator^(Mod_Int a,_Tp p){return _pow(a.val,p);}constexpr friend inline Mod_Int&operator+=(Mod_Int&a,Mod_Int b){return a=_add(a.val,b.val);}constexpr friend inline Mod_Int&operator-=(Mod_Int&a,Mod_Int b){return a=_sub(a.val,b.val);}constexpr friend inline Mod_Int&operator*=(Mod_Int&a,Mod_Int b){return a=_mul(a.val,b.val);}constexpr friend inline Mod_Int&operator/=(Mod_Int&a,Mod_Int b){return a=_mul(a.val,inv(b.val));}template<typename _Tp,typename=std::enable_if_t<std::is_integral<_Tp>::value>>constexpr friend inline Mod_Int&operator^=(Mod_Int&a,_Tp p){return a=_pow(a.val,p);}constexpr friend inline bool operator==(Mod_Int a,Mod_Int b){return a.val==b.val;}constexpr friend inline bool operator!=(Mod_Int a,Mod_Int b){return a.val!=b.val;}constexpr Mod_Int&operator++(){this->val+1==mod?this->val=0:++this->val;return*this;}constexpr Mod_Int&operator--(){this->val==0?this->val=mod-1:--this->val;return*this;}constexpr Mod_Int operator++(int){Mod_Int res=*this;this->val+1==mod?this->val=0:++this->val;return res;}constexpr Mod_Int operator--(int){Mod_Int res=*this;this->val==0?this->val=mod-1:--this->val;return res;}friend std::istream&operator>>(std::istream&is,Mod_Int<mod,T,S>&x){T ipt;return is>>ipt,x=ipt,is;}friend std::ostream&operator<<(std::ostream&os,Mod_Int<mod,T,S>x){return os<<x.val;}protected:T val;static constexpr inline T _add(T a,T b){return a>=mod-b?a+b-mod:a+b;}static constexpr inline T _sub(T a,T b){return a<b?a-b+mod:a-b;}static constexpr inline T _mul(T a,T b){return static_cast<S>(a)*b%mod;}template<typename _Tp,typename=std::enable_if_t<std::is_integral<_Tp>::value>>static constexpr inline T _pow(T a,_Tp p){T res=1;for(;p;p>>=1,a=_mul(a,a))if(p&1)res=_mul(res,a);return res;}};using mint=Mod_Int<>;using mod_t=mint;constexpr mint operator""_m(unsigned long long x){return mint(x);}constexpr mint operator""_mod(unsigned long long x){return mint(x);}}using namespace Mod_Int_Class;namespace FASTIO{const int MAX=1<<26;char buf[MAX],*ip=buf,obuf[MAX],*op=obuf;template<typename T>inline void read(T&x){x=0;char ch=*ip++;for(;ch<48;ch=*ip++);for(;ch>=48;ch=*ip++)x=(x<<3)+(x<<1)+(ch^48);}template<typename T>inline void write(T x){static short stack[20],top(0);do stack[++top]=x%10;while(x/=10);while(top)*FASTIO::op++=(stack[top--]|48);}}namespace $yzh{const int N=100010;int n,m,X;mint inv[N],ans[N];namespace sub1{struct Matrix{mint a[4][4];inline void init(){memset(a,0x00,sizeof(a));}inline void unit(){a[0][0]=1;a[1][1]=1;a[2][2]=1;a[3][3]=1;}mint*operator[](int x){return a[x];}mint const*operator[](int x)const{return a[x];}friend Matrix operator*(const Matrix&a,const Matrix&b){Matrix res;res[0][0]=a[0][0]*b[0][0]+a[0][1]*b[1][0]+a[0][2]*b[2][0]+a[0][3]*b[3][0];res[0][1]=a[0][0]*b[0][1]+a[0][1]*b[1][1]+a[0][2]*b[2][1]+a[0][3]*b[3][1];res[0][2]=a[0][0]*b[0][2]+a[0][1]*b[1][2]+a[0][2]*b[2][2]+a[0][3]*b[3][2];res[0][3]=a[0][0]*b[0][3]+a[0][1]*b[1][3]+a[0][2]*b[2][3]+a[0][3]*b[3][3];res[1][0]=a[1][0]*b[0][0]+a[1][1]*b[1][0]+a[1][2]*b[2][0]+a[1][3]*b[3][0];res[1][1]=a[1][0]*b[0][1]+a[1][1]*b[1][1]+a[1][2]*b[2][1]+a[1][3]*b[3][1];res[1][2]=a[1][0]*b[0][2]+a[1][1]*b[1][2]+a[1][2]*b[2][2]+a[1][3]*b[3][2];res[1][3]=a[1][0]*b[0][3]+a[1][1]*b[1][3]+a[1][2]*b[2][3]+a[1][3]*b[3][3];res[2][0]=a[2][0]*b[0][0]+a[2][1]*b[1][0]+a[2][2]*b[2][0]+a[2][3]*b[3][0];res[2][1]=a[2][0]*b[0][1]+a[2][1]*b[1][1]+a[2][2]*b[2][1]+a[2][3]*b[3][1];res[2][2]=a[2][0]*b[0][2]+a[2][1]*b[1][2]+a[2][2]*b[2][2]+a[2][3]*b[3][2];res[2][3]=a[2][0]*b[0][3]+a[2][1]*b[1][3]+a[2][2]*b[2][3]+a[2][3]*b[3][3];res[3][0]=a[3][0]*b[0][0]+a[3][1]*b[1][0]+a[3][2]*b[2][0]+a[3][3]*b[3][0];res[3][1]=a[3][0]*b[0][1]+a[3][1]*b[1][1]+a[3][2]*b[2][1]+a[3][3]*b[3][1];res[3][2]=a[3][0]*b[0][2]+a[3][1]*b[1][2]+a[3][2]*b[2][2]+a[3][3]*b[3][2];res[3][3]=a[3][0]*b[0][3]+a[3][1]*b[1][3]+a[3][2]*b[2][3]+a[3][3]*b[3][3];return res;}friend Matrix&operator*=(Matrix&a,const Matrix&b){return a=a*b;}};struct Segment_Tree{Matrix a[N<<1];int ls[N<<1],rs[N<<1];bool tag[N<<1];int pcnt,rt;inline int newNode(){a[++pcnt].init();a[pcnt].unit();ls[pcnt]=rs[pcnt]=0;tag[pcnt]=false;return pcnt;}void modify(int&idx,int trl,int trr,int p,const Matrix&x){if(!idx)idx=newNode();if(tag[idx])a[idx]*=x;else a[idx]=x,tag[idx]=true;if(trl==trr)return;int mid=(trl+trr)>>1;if(p<=mid)modify(ls[idx],trl,mid,p,x);else modify(rs[idx],mid+1,trr,p,x);}inline void modify(int p,const Matrix&x){modify(rt,1,n,p,x);}inline void build(){pcnt=0,rt=0;}void query(int idx,int trl,int trr,int l,int r,Matrix&x){if(l<=trl&&trr<=r){if(tag[idx])x*=a[idx];return;}int mid=(trl+trr)>>1;if(ls[idx]&&l<=mid)query(ls[idx],trl,mid,l,r,x);if(rs[idx]&&r>mid)query(rs[idx],mid+1,trr,l,r,x);}inline Matrix query(int l,int r){Matrix t;t.init();t.unit();if(rt)query(rt,1,n,l,r,t);return t;}};struct Bit_Tree{Matrix a[N];int T[N],timer;inline void refresh(int x){if(T[x]!=timer){T[x]=timer;a[x].init();a[x].unit();}}inline void modify(int p,const Matrix&x){for(;p;p&=p-1)if(T[p]==timer)a[p]*=x;else T[p]=timer,a[p]=x;}inline void build(){++timer;}inline Matrix querysuf(int p)const{Matrix t;t.init();t.unit();for(;p<=n;p+=p&-p)if(T[p]==timer)t*=a[p];return t;}};struct Question{int idx,l,r,T;}q[N];Matrix qv[N];int qcnt;void init(){}inline void add1(int l,int r){q[++qcnt]={-1,l,r,0};q[qcnt].T=qcnt;}inline void add2(int l,int r,int idx){assert(l>1);--l;q[++qcnt]={idx,l,r,0};q[qcnt].T=qcnt;qv[idx].init();qv[idx].unit();}Bit_Tree t1;Segment_Tree t2,t3;void solve(int l,int r){if(l==r)return;int mid=(l+r)>>1;solve(l,mid),solve(mid+1,r);t1.build(),t2.build();for(int i=mid+1,j=l;i<=r;++i){for(;j<=mid&&q[j].l<=q[i].l;++j)if(!~q[j].idx){int x=q[j].r;mint p=inv[q[j].r-q[j].l+1];Matrix t;t.init();t[0b10][0b00]=p;t[0b01][0b00]=p;t[0b00][0b00]=1-p*2;t[0b11][0b01]=p;t[0b00][0b01]=p;t[0b01][0b01]=1-p*2;t[0b00][0b10]=p;t[0b11][0b10]=p;t[0b10][0b10]=1-p*2;t[0b01][0b11]=p;t[0b10][0b11]=p;t[0b11][0b11]=1-p*2;t1.modify(x,t);t.init();t[0b00][0b00]=1-p;t[0b10][0b00]=p;t[0b10][0b10]=1-p;t[0b00][0b10]=p;t[0b01][0b01]=1-p;t[0b11][0b01]=p;t[0b11][0b11]=1-p;t[0b01][0b11]=p;t2.modify(x,t);}if(~q[i].idx){qv[q[i].idx]*=t1.querysuf(q[i].r);if(q[i].l<=q[i].r-1)qv[q[i].idx]*=t2.query(q[i].l,q[i].r-1);}}inplace_merge(q+l,q+mid+1,q+r+1,[](const Question&a,const Question&b)->bool{return a.l<b.l;});}void solve2(int l,int r){if(l==r)return;int mid=(l+r)>>1;solve2(l,mid),solve2(mid+1,r);t3.build();for(int i=r,j=mid;i>=mid+1;--i){for(;j>=l&&q[j].r>=q[i].r;--j)if(!~q[j].idx){int x=q[j].l;mint p=inv[q[j].r-q[j].l+1];Matrix t;t.init();t[0b00][0b00]=1-p;t[0b01][0b00]=p;t[0b01][0b01]=1-p;t[0b00][0b01]=p;t[0b10][0b10]=1-p;t[0b11][0b10]=p;t[0b11][0b11]=1-p;t[0b10][0b11]=p;t3.modify(x,t);}if(~q[i].idx){if(q[i].l+1<=q[i].r)qv[q[i].idx]*=t3.query(q[i].l+1,q[i].r);}}inplace_merge(q+l,q+mid+1,q+r+1,[](const Question&a,const Question&b)->bool{return a.r<b.r;});}void solve(){solve(1,qcnt);sort(q+1,q+qcnt+1,[](const Question&a,const Question&b)->bool{return a.T<b.T;});solve2(1,qcnt);for(int l=1;l<=qcnt;++l)if(~q[l].idx){Matrix t;t.init();t[0][0]=1;t*=qv[q[l].idx];ans[q[l].idx]=t[0][0]+t[0][3];}}}namespace sub2{struct Matrix{mint a[2][2];inline void init(){memset(a,0x00,sizeof(a));}inline void unit(){a[0][0]=1;a[1][1]=1;}mint*operator[](int x){return a[x];}mint const*operator[](int x)const{return a[x];}friend Matrix operator*(const Matrix&a,const Matrix&b){Matrix res;res[0][0]=a[0][0]*b[0][0]+a[0][1]*b[1][0];res[0][1]=a[0][0]*b[0][1]+a[0][1]*b[1][1];res[1][0]=a[1][0]*b[0][0]+a[1][1]*b[1][0];res[1][1]=a[1][0]*b[0][1]+a[1][1]*b[1][1];return res;}friend Matrix&operator*=(Matrix&a,const Matrix&b){return a=a*b;}};struct Segment_Tree{Matrix a[N<<1];int ls[N<<1],rs[N<<1];bool tag[N<<1];int pcnt,rt;inline int newNode(){a[++pcnt].init();a[pcnt].unit();ls[pcnt]=rs[pcnt]=0;tag[pcnt]=false;return pcnt;}void modify(int&idx,int trl,int trr,int l,int r,const Matrix&x){if(!idx)idx=newNode();if(l<=trl&&trr<=r){if(tag[idx])a[idx]*=x;else a[idx]=x,tag[idx]=true;return;}int mid=(trl+trr)>>1;if(l<=mid)modify(ls[idx],trl,mid,l,r,x);if(r>mid)modify(rs[idx],mid+1,trr,l,r,x);}inline void modify(int l,int r,const Matrix&x){modify(rt,1,n,l,r,x);}inline void build(){pcnt=0,rt=0;}void query(int idx,int trl,int trr,int p,Matrix&x){if(tag[idx])x*=a[idx];if(trl==trr)return;int mid=(trl+trr)>>1;if(ls[idx]&&p<=mid)query(ls[idx],trl,mid,p,x);else if(rs[idx]&&p>mid)query(rs[idx],mid+1,trr,p,x);}inline Matrix query(int p){Matrix t;t.init();t.unit();if(rt)query(rt,1,n,p,t);return t;}};Segment_Tree yzh;int X;inline void init(){yzh.build(),X=0;}void add1(int l,int r){Matrix t;t.init();mint p=inv[r-l+1];t[0][0]=1-p,t[0][1]=p;t[1][0]=p,t[1][1]=1-p;yzh.modify(l,r,t);++X;}void add2(int x,int idx){Matrix res=yzh.query(x);Matrix t;t.init();t[0][0]=1,t[0][1]=0;t=t*res;ans[idx]=t[0][X&1];}void solve(){}}bool isQ[N];void solve(){FASTIO::read(n),FASTIO::read(m);inv[1]=1;for(int i=2;i<=n;++i)inv[i]=-(mint::mod/i)*inv[mint::mod%i],assert(inv[i]*i==1);sub1::init(),sub2::init();for(int op,l,r,i=1;i<=m;++i){FASTIO::read(op);FASTIO::read(l),FASTIO::read(r);if(op==1){sub1::add1(l,r);sub2::add1(l,r);}else{isQ[i]=true;if(l>1){sub1::add2(l,r,i);}else{sub2::add2(r,i);}}}sub1::solve(),sub2::solve();for(int i=1;i<=m;++i)if(isQ[i])FASTIO::write(ans[i].raw()),*FASTIO::op++ = ('\n');}}int main(){freopen("bit.in","r",stdin);freopen("bit.out","w",stdout);fread(FASTIO::buf,1,FASTIO::MAX,stdin);$yzh::solve();fwrite(FASTIO::obuf,1,FASTIO::op-FASTIO::obuf,stdout);return 0;}
本文作者:XuYueming,转载请注明原文链接:https://www.cnblogs.com/XuYueming/p/18697443。
若未作特殊说明,本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】