「ZJOI2017」树状数组 题解

前言

题目链接:洛谷UOJLOJ

UOJ 上有很强的数据。

题意简述

yzh 做 OI 题维护序列 {an}

她实现了一个后缀和查询函数 f(x)={0 if x=0i=xnai otherwise ,和一个区间查询函数 g(l,r)=f(r)f(l1),显然,她并没有意识到这里有些小问题。以上运算都是在 F2 意义下进行的。

初始 ai=0。这道问题有 m 次操作,每种操作类型为单点加一、区间查询。单点加参数是一个区间 [li,ri],表示随机选取 p[li,ri],让 apap+1;区间查询是正常的区间查询和在 F2 意义下的结果。

现在,你需要对每一个查询,求出她错误的实现依然能够得到正确答案的概率,对 998244353 取模。

n,m105

题目分析

初步分析

肯定要分析 g(l,r) 什么时候正确。不妨对 l=1 与否进行讨论。

  1. l=1
    此时 f(l1)=f(0)=0

    g(l,r)=i=lraii=rnai=i=lraii=r+1nai=i=lr1aii=1naii=1rai=i=lr1aii=1naii=1r1aiar=i=lr1aii=1naiar=2i=lr1ai

    注意到在模 2 意义下,右侧为 0

    i=1nai=ar

    左侧就是到目前位置我们进行了多少次操作,这个随便维护。我们就把问题具象化成求某一个位置为 0/1 的概率。
  2. l>1

    g(l,r)=i=lraii=rnaii=l1nai=i=lraii=lrai+i=l1r1ai=0al1+ar+2i=lr1ai=0al1+ar=0al1=ar

    问题简化成求两个位置值相等的概率。

暴力模拟

我们考虑一个 O(nm) 的算法。

对于第一个问题(求 ai=x 的概率),我们考虑维护 f[0/1] 表示 ai=0/1 的概率,初始 f[0]=1,f[1]=0

O(m) 地枚举一个包含 i 的修改 [l,r]i,那么它恰好修改到 ai 的概率为 p=1rl+1。也就是说,aip 的概率变化,1p 的概率不变化。那么 f[o]pf[¬o]+(1p)f[o]。于是解决了该问题。

不怎么有用的发现

事实上,我们只维护 f[0]/f[1] 即可,因为 f[0]+f[1]1

对于第二个问题,我们想当然地求出 fl1[0/1],fr[0/1],答案为 fl1[0]fr[0]+fl1[1]fr[1]。但是,这是错误的。

我们发现,有些操作对 al1,ar 的影响不是独立的。对于一个修改 [ql,qr][l1,r],那么倘若随机到了 al1,那么此时 ar 必不可能被修改。这看上去似乎很棘手,事实上,我们仅需将状态扩充至 f[0/1][0/1] 表示 al1,ar 的值即可。这样,对于完全包含 [l1,r] 的转移为 f[x][y]pf[¬x][y]+pf[x][¬y]+(12p)f[x][y]。剩下仅包含一个端点的转移类似第一个问题。初值 f[0][0]=1,其他为 0

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());
}
}
}
}

抽丝剥茧,转化为熟悉的模型

问题都分析到这了,矩阵呼之欲出了。各种数据结构在你脑海里的形象愈发清晰。

问题一

先来看看好下手的问题一。我们把 f[0/1] 看做一个 1×2 的矩阵,那么对于一个修改,就可以构造出转移矩阵:

[f[0]f[1]]×[1ppp1p]=[f[0]f[1]]

然后,我们请出一个能够区间乘矩阵,单点查询的数据结构。线段树是也。

于是,我们在线地解决了问题一,修改 / 询问 O(w3logn),其中 w=2

问题二

类似的,我们把 f[0/1][0/1] 拍扁成一个 1×4 的矩阵,并构造出转移矩阵。

  1. 完全包含

[f[0][0]f[0][1]f[1][0]f[1][1]]×[12pppp12ppp12pppp12p]=[f[0][0]f[0][1]f[1][0]f[1][1]]

  1. 仅包含左端点

[f[0][0]f[0][1]f[1][0]f[1][1]]×[1pp1pp1ppp1p]=[f[0][0]f[0][1]f[1][0]f[1][1]]

  1. 仅包含右端点

[f[0][0]f[0][1]f[1][0]f[1][1]]×[1ppp1p1ppp1p]=[f[0][0]f[0][1]f[1][0]f[1][1]]

但是,这时候,我们发现有了区间包含关系的限制,十分地不好搞。

发现如果拍到一个二维笛卡尔坐标系上,这是二维数点状物。俗话说得好,二维数点,静态扫描线而动态 CDQ 也。这里我们使用 CDQ 分治就能解决问题。

三维偏序,一维时间,时间轴分治解决;再一维双指针维护解决;最后一维,数据结构解决。

我们先递归解决 L=[l,mid],R=(mid,r],然后考虑 L 中的修改对 R 中的询问产生的影响。

这里我们先递归了 R,而不是递归 L,然后解决跨过分治中心,再递归 R,是因为修改的顺序并不影响答案,所以是对的。事实上,严格按照修改的顺序分治也可以。

考虑完全包含、包含左端点两种情况,包含右端点类似。

我们先分别把 L,R 里所有操作按照左端点升序排序。

考虑以此枚举 iR,同时双指针维护所有左端点小于等于 i 的左端点的 j

上图中,中间灰色的线表示分治中心,右侧黑色的竖线表示我们枚举的 i。我们可以把左侧的 j 分为三类。

  • 红色:这一类右端点已经小于 i 的左端点,没有用处,忽略。
  • 蓝色:这一类右端点大于等于 i 的右端点,是完全包含类型。
  • 绿色:这一类右端点小于 i 的右端点,仅包含 i 的左端点。

所以我们情不自禁使用两个数据结构,分别维护两种转移矩阵。查询的时候,按照需要查询即可。这个数据结构需要支持单点修改,区间查询矩阵乘。动态开点线段树即可。

于是,我们离线地解决了问题二。时间复杂度不难分析出为 O(w3mlogm(logm+logn)),其中 w=4

收尾工作(卡常

整体空间复杂度很不错,差不多是线性的 O(w2(n+m))

整体时间复杂度在两只 log 的基础上有矩阵乘法 w3 的加持,十分难受。

我们发现,由于我们提到修改的顺序不影响答案,那么我们把处理右端点提出来,做两次 CDQ 分治,这样,每次分治内部不需要排序,而是使用原地归并。将 (logm+logn) 因子优化为了 logn 因子。

我们再次发现,在处理完全包含类型时,我们的区间查询是后缀查询,那么用一棵树状数组代替一棵线段树,时间复杂度没有变化,但是常数更小了。由于我不会动态开点树状数组这种科技,所以采用了时间戳清空。

我们又又发现,线段树可以搞一搞。我们多维护一个 bool 类型的标记,表示这个节点的矩阵是不是单位矩阵,在询问时,如果遇到一个单位矩阵,就不进行矩阵乘法。在新建节点时,我们采用直接赋值,而不是先弄成单位矩阵,再做一次矩阵乘法。

我们努努力,把矩阵乘法手动做循环展开。

我们上传统手艺,加上超级快读快写。

我们发现,我们终于过了这题……

代码

原味代码(920 行)
#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 分治解决
左端点,归并解决
右端点,数据结构
*/
正常代码(673 行,略去取模板子)
#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;}
posted @   XuYueming  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示