Loj 2980. 「THUSCH 2017」大魔法師 線段樹維護矩陣
阿新 • • 發佈:2020-09-16
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\)
當\(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; }