「THUSCH 2017」大魔法師
阿新 • • 發佈:2020-11-16
這道題目的難點在於要發現正解是矩陣
這個題目的正解就是:矩陣乘法+\(luogu\)線段樹模板2
規定矩陣:
\[ \left[ \begin{matrix} A \\ B \\ C \end{matrix} \right] \tag{1} \]首先對於操作一:
\[ \left[ \begin{matrix} 1 & 1 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{matrix} \right] \tag{2} \]矩陣\(1\)*矩陣\(2\)
對於操作2:
\[ \left[ \begin{matrix} 1 & 0 & 0 \\ 0 & 1 & 1 \\ 0 & 0 & 1 \end{matrix} \right] \tag{3} \]矩陣\(1\) * 矩陣 \(3\)得到:
\[ \left[ \begin{matrix} A \\ B+C \\ C \end{matrix} \right] \]對於操作三:
\[ \left[ \begin{matrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 1 & 0 & 1 \end{matrix} \right] \tag{4} \]矩陣\(1\) * 矩陣\(4\)得到:
\[ \left[ \begin{matrix} A \\ B \\ C+A \end{matrix} \right] \]對於操作四:
\[ \left[ \begin{matrix} v \\ 0 \\ 0 \end{matrix} \right] \tag{5} \]矩陣\(1\) + \(矩陣5\)得到:
\[ \left[ \begin{matrix} A + v \\ B \\ C \end{matrix} \right] \]對於操作5:
\[ \left[ \begin{matrix} 1 & 0 & 0 \\ 0 & v & 0 \\ 0 & 0 & 1 \end{matrix} \right] \tag{6} \]矩陣\(1\) * 矩陣\(6\)得到:
\[ \left[ \begin{matrix} A \\ B*v \\ C \end{matrix} \right] \]對於操作六:
\[ \left[ \begin{matrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 0 \end{matrix} \right] \tag{7} \]\[ \left[ \begin{matrix} 0 \\ 0 \\ v \end{matrix} \right] \tag{8} \]矩陣\(1\) * \(矩陣7 + 矩陣8\)得到:
\[ \left[ \begin{matrix} A \\ B \\ v \end{matrix} \right] \]綜上,就完成了六種修改操作。很簡單的發現,這個東西用線段樹比較好維護。
考慮如何下傳標記。
這裡發現一共要實現矩陣的乘法以及加法。
類似於線段樹的模板二,也要支援序列的乘法以及加法。
將線段樹模板二的序列乘法加法改為矩陣乘法加法即可。
下傳:先乘後加
假設現在的數字為:\((x + lazadd) * lazmul\)(\(lazadd表示加法懶標記矩陣,\)lazmul表示乘法懶標記矩陣\(,\)x表示原來的數字$)
現在要乘以一個\(t\),加上一個\(k\),先將\(lazadd以及lazmul還有sum\)都乘以\(矩陣t\),然後再將\(lazadd還有sum\)加上\(矩陣k\)即可。
跳過這段辣雞噁心醜陋的程式碼點我
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 250000 + 50,Mod = 998244353;
int n,Q;
int data[MAXN][3];
int mul1[3][3],mul2[3][3],mul3[3][3],mul5[3][3],mul6[3][3],Sum[3],M[3][3];
struct Node {
int sum[3];
int lazadd[3];
int lazmul[3][3];
int l , r ;
void Clean()
{
for(int i = 0 ; i <= 2 ; i ++)
{
lazadd[i] = 0;
for(int j = 0 ; j <= 2; j ++)
lazmul[i][j] = 0;
lazmul[i][i] = 1;
}
return ;
}
void ad(int Mul[3][3],int add[3])
{
int C[3][3] = {0};
for(int i = 0 ; i <= 2 ; i ++)
{
for(int j = 0 ; j <= 2 ; j ++)
for(int k = 0 ; k <= 2 ; k ++)
C[i][j] += (lazmul[k][j] * Mul[i][k]) % Mod,C[i][j] %= Mod;
}
for(int i = 0 ; i <= 2 ; i ++)
for(int j = 0 ; j <= 2 ; j ++)
lazmul[i][j] = C[i][j],C[i][j] = 0;
for(int i = 0 ; i <= 2 ; i ++)
{
for(int k = 0 ; k <= 2 ; k ++)
C[i][0] += (Mul[i][k] * lazadd[k]) % Mod,C[i][0] %= Mod;
}
for(int i = 0 ; i <= 2 ; i ++)
lazadd[i] = C[i][0],C[i][0] = 0,lazadd[i] += add[i],lazadd[i] %= Mod;
for(int i = 0 ; i <= 2 ; i ++)
{
for(int k = 0 ; k <= 2 ; k ++)
C[i][0] += (Mul[i][k] * sum[k]) % Mod,C[i][0] %= Mod;
}
for(int i = 0 ; i <= 2 ; i ++)
sum[i] = C[i][0],sum[i] %= Mod,C[i][0] = 0,sum[i] += ((r - l + 1) * add[i]) % Mod,sum[i] %= Mod;
return ;
}
} T[MAXN * 4];
struct Output
{
int A,B,C;
};
bool pd(int x)
{
if(T[x].lazadd[0] || T[x].lazadd[1] || T[x].lazadd[2])return 1;
for(int i = 0 ; i <= 2 ; i ++)
for(int j = 0 ; j <= 2 ; j ++)
if(M[i][j] != T[x].lazmul[i][j])return 1;
return 0;
}
void pushdown(int x)
{
if(pd(x) == 0) return;
T[x << 1].ad(T[x].lazmul,T[x].lazadd);
T[x << 1 | 1].ad(T[x].lazmul,T[x].lazadd);
T[x].Clean();
return ;
}
void build(int x,int l,int r)
{
T[x].l = l , T[x].r = r;
T[x].Clean();
if(l == r)
{
T[x].sum[0] = data[l][0];T[x].sum[0] %= Mod;
T[x].sum[1] = data[l][1];T[x].sum[1] %= Mod;
T[x].sum[2] = data[l][2];T[x].sum[2] %= Mod;
return ;
}dianwo
int mid = ( l + r ) >> 1;
build(x << 1 , l , mid );
build(x << 1 | 1 , mid + 1 , r);
T[x].sum[0] = T[x << 1].sum[0] % Mod + T[x << 1 | 1].sum[0] % Mod;T[x].sum[0] %= Mod;
T[x].sum[1] = T[x << 1].sum[1] % Mod + T[x << 1 | 1].sum[1] % Mod;T[x].sum[1] %= Mod;
T[x].sum[2] = T[x << 1].sum[2] % Mod + T[x << 1 | 1].sum[2] % Mod;T[x].sum[2] %= Mod;
return ;
}
void prepare()
{
for(int i = 0 ; i <= 2 ; i ++)
{
for(int j = 0 ; j <= 2 ; j ++)
mul1[i][j] = mul2[i][j] = mul3[i][j] = mul5[i][j] = mul6[i][j] = 0ll;
mul1[i][i] = mul2[i][i] = mul3[i][i] = mul5[i][i] = mul6[i][i] = 1ll;
M[i][i] = 1;
}
mul1[0][1] = 1ll;
mul2[1][2] = 1ll;
mul3[2][0] = 1ll;
mul6[2][2] = 0ll;
return ;
}
Output Add(Output A, Output B)
{
A.A += B.A;A.A %= Mod;
A.B += B.B;A.B %= Mod;
A.C += B.C;A.C %= Mod;
return A;
}
Output GetSum(int x,int l,int r)
{
Output Ans;
Ans.A = Ans.B = Ans.C = 0ll;
if(T[x].l >= l && T[x].r <= r)
{
Ans.A = T[x].sum[0] % Mod;
Ans.B = T[x].sum[1] % Mod;
Ans.C = T[x].sum[2] % Mod;
return Ans;
}
pushdown(x);
int mid = (T[x].l + T[x].r) >> 1;
if(l <= mid)Ans = Add(Ans,GetSum(x << 1 , l , r));
if(r > mid)Ans = Add(Ans,GetSum(x << 1 | 1 , l, r));
Ans.A %= Mod;
Ans.B %= Mod;
Ans.C %= Mod;
return Ans;
}
void change(int x,int l,int r,int op)
{
if(T[x].l >= l && T[x].r <= r)
{
if(op == 1)T[x].ad(mul1,Sum);
if(op == 2)T[x].ad(mul2,Sum);
if(op == 3)T[x].ad(mul3,Sum);
if(op == 4)T[x].ad(M,Sum);
if(op == 5)T[x].ad(mul5,Sum);
if(op == 6)T[x].ad(mul6,Sum);
return ;
}
pushdown(x);
int mid = (T[x].l + T[x].r) >> 1;
if(l <= mid)change(x << 1 , l , r , op);
if(r > mid)change(x << 1 | 1 , l, r , op);
T[x].sum[0] = T[x << 1].sum[0] % Mod + T[x << 1 | 1].sum[0] % Mod;T[x].sum[0] %= Mod;
T[x].sum[1] = T[x << 1].sum[1] % Mod + T[x << 1 | 1].sum[1] % Mod;T[x].sum[1] %= Mod;
T[x].sum[2] = T[x << 1].sum[2] % Mod + T[x << 1 | 1].sum[2] % Mod;T[x].sum[2] %= Mod;
return ;
}
signed main()
{
cin >> n;
for(int i = 1 ; i <= n ; i ++)
{
int A,B,C;
cin >> A >> B >> C;
data[i][0] = A;
data[i][1] = B;
data[i][2] = C;
}
build(1 , 1 , n);
prepare();
cin >> Q;
for(int i = 1 ; i <= Q ; i ++)
{
int op,l,r,v;
cin >> op >> l >> r ;
if( 4ll <= op && op <= 6ll )cin >> v;
if(op == 4)
Sum[0] = v,Sum[1] = Sum[2] = 0ll;
if(op == 6)
Sum[0] = Sum[1] = 0ll ,Sum[2] = v;
if(op == 5)mul5[1][1] = v;
if(op <= 6)change(1 , l , r , op);
if(op == 7)
{
Output Ans = GetSum(1 , l , r);
cout << Ans.A % Mod;putchar(' ');
cout << Ans.B % Mod;putchar(' ');
cout << Ans.C % Mod;putchar('\n');
}
Sum[0] = Sum[1] = Sum[2] = 0ll;
}
return 0;
}
後話:
一開始我忘記初始化\(Ans(那一個記錄答案的結構體)\),然後就不停的隨機輸出錯誤答案,希望大家不要犯這種錯誤。
還有就是(這個題真的難寫!!!)
(我勸你好(\(第四聲\))自為之,好(第四聲)好反思,以後,不要再犯) ------ txdy_zhy