Loj 2980. 「THUSCH 2017」大魔法师 线段树维护矩阵
Loj 2980. 「THUSCH 2017」大魔法师
线段树维护矩阵。
可以对每个节点维护这样一个矩阵:\(\begin{bmatrix} A\\B\\C\\1 \end{bmatrix}\)
为啥要多个1呢?因为会有\(A += v,C = v\)的操作,这样好转移。
当\(opt == 1\)时,转移矩阵为:\(\begin{bmatrix} 1&1&0&0 \\ 0&1&0&0\\0&0&1&0\\0&0&0&1\end{bmatrix}\)
当\(opt == 2,3\)时,转移矩阵与1类似。
当\(opt == 4\)时,转移矩阵为:\(\begin{bmatrix} 1&0&0&v \\ 0&1&0&0\\0&0&1&0\\0&0&0&1\end{bmatrix}\)
当\(opt == 5\)时,转移矩阵为:\(\begin{bmatrix} 1&0&0&0 \\ 0&v&0&0\\0&0&1&0\\0&0&0&1\end{bmatrix}\)
当\(opt == 6\)时,转移矩阵为:\(\begin{bmatrix} 1&0&0&0 \\ 0&1&0&0\\0&0&0&v\\0&0&0&1\end{bmatrix}\)
#include <bits/stdc++.h>
#define ls(o) (o << 1)
#define rs(o) (o << 1 | 1)
#define mid ((l + r) >> 1)
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 2.5e5 + 5, mod = 998244353;
int n, m, ansa, ansb, ansc;
struct mat {
int v[4][4];
mat() { memset(v, 0, sizeof(v)); }
friend mat operator * (const mat &a, const mat &b) {
mat c;
for(int i = 0;i <= 3; i++) for(int j = 0;j <= 3; j++) c.v[i][j] = 0;
for(int i = 0;i <= 3; i++)
for(int j = 0;j <= 3; j++)
for(int k = 0;k <= 3; k++)
if(a.v[i][k] && b.v[k][j]) //减小常数
c.v[i][j] = (c.v[i][j] + 1ll * a.v[i][k] * b.v[k][j] % mod) % mod;
return c;
}
} orz, turn;
struct tree { mat sum, tag; } t[N << 2];
void up(int o) {
for(int i = 0;i <= 3; i++)
t[o].sum.v[i][0] = (t[ls(o)].sum.v[i][0] + t[rs(o)].sum.v[i][0]) % mod;
}
void build(int o, int l, int r) {
t[o].tag = orz;
if(l == r) {
t[o].sum.v[0][0] = read(); t[o].sum.v[1][0] = read();
t[o].sum.v[2][0] = read(); t[o].sum.v[3][0] = 1;
return ;
}
build(ls(o), l, mid); build(rs(o), mid + 1, r);
up(o);
}
void down(int o) {
t[ls(o)].tag = t[o].tag * t[ls(o)].tag; //这里注意顺序别搞反
t[ls(o)].sum = t[o].tag * t[ls(o)].sum;
t[rs(o)].tag = t[o].tag * t[rs(o)].tag;
t[rs(o)].sum = t[o].tag * t[rs(o)].sum;
t[o].tag = orz;
}
void change(int o, int l, int r, int x, int y) {
if(x <= l && y >= r) {
t[o].tag = turn * t[o].tag; //这里注意顺序别搞反
t[o].sum = turn * t[o].sum;
return ;
}
down(o);
if(x <= mid) change(ls(o), l, mid, x, y);
if(y > mid) change(rs(o), mid + 1, r, x, y);
up(o);
}
void query(int o, int l, int r, int x, int y) {
if(x <= l && y >= r) {
ansa += t[o].sum.v[0][0]; ansb += t[o].sum.v[1][0]; ansc += t[o].sum.v[2][0];
ansa %= mod; ansb %= mod; ansc %= mod; return ;
}
down(o);
if(x <= mid) query(ls(o), l, mid, x, y);
if(y > mid) query(rs(o), mid + 1, r, x, y);
}
int main() {
n = read();
for(int i = 0;i <= 3; i++) orz.v[i][i] = 1; //单位矩阵
build(1, 1, n);
m = read();
for(int i = 1, opt, x, y, v;i <= m; i++) {
opt = read(); x = read(); y = read();
if(opt >= 4 && opt <= 6) v = read();
turn = orz;
if(opt == 1) turn.v[0][1] = 1, change(1, 1, n, x, y);
if(opt == 2) turn.v[1][2] = 1, change(1, 1, n, x, y);
if(opt == 3) turn.v[2][0] = 1, change(1, 1, n, x, y);
if(opt == 4) turn.v[0][3] = v, change(1, 1, n, x, y);
if(opt == 5) turn.v[1][1] = v, change(1, 1, n, x, y);
if(opt == 6) turn.v[2][2] = 0, turn.v[2][3] = v, change(1, 1, n, x, y);
if(opt == 7) ansa = ansb = ansc = 0, query(1, 1, n, x, y), printf("%d %d %d\n", ansa, ansb, ansc);
}
return 0;
}