[LOJ2980]「THUSCH 2017」大魔法师
题目链接:
把\(A,B,C\)组成矩阵\([A,B,C]\),那么每一次操作就可以用矩阵表示:
- \(A=A+B\)
\(\times \begin{bmatrix}1&0&0\\1&1&0\\0&0&1\end{bmatrix}\)
\(B=B+C,C=C+A\)类似。
- \(A=A+v\)
\(+[v,0,0]\)
- \(B=B*v\)
\(\times \begin{bmatrix}1&0&0\\0&v&0\\0&0&1\end{bmatrix}\)
- \(C=v\)
\(\times \begin{bmatrix}1&0&0\\1&0&0\\0&0&0\end{bmatrix}\)
\(+[0,0,v]\)
然后线段树区间操作即可,注意优先级。
每一次乘法标记清空时要置为单位矩阵。
时间复杂度 \(O(27n\log n)\)
代码(常数爆炸):
#include <cstdio>
#include <cctype>
#include <cstring>
#define rint register int
typedef long long ll;
#define Getchar (p1==p2&&(p2=(p1=In)+fread(In,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char In[1<<21],*p1=In,*p2=In,Ch,Out[8000005],*Outp=Out,St[15],*Tp=St;
inline int Getint(rint x=0)
{
while(!isdigit(Ch=Getchar));
for(;isdigit(Ch);Ch=Getchar)x=x*10+(Ch^48);
return x;
}
inline void Putint(int x,const char c)
{
do *Tp++=x%10^48;while(x/=10);
do *Outp++=*--Tp;while(Tp!=St);
*Outp++=c;
}
const int Mod=998244353;
inline int Add(int a,int b){return (a+=b)>=Mod?a-Mod:a;}
struct Matrix
{
int n,m,a[3][3];
inline void Clear(){memset(a,0,sizeof a);}
inline Matrix(const int ns=0,const int ms=0){n=ns,m=ms,Clear();}
inline void Init(const int ns,const int ms){n=ns,m=ms;}
inline void IOne(){for(rint i=0;i<n;++i)a[i][i]=1;}
inline Matrix operator+(const Matrix &o)const
{
Matrix Res(n,m);
for(rint i=0;i<n;++i)
for(rint j=0;j<m;++j)
Res.a[i][j]=Add(a[i][j],o.a[i][j]);
return Res;
}
inline Matrix operator*(const int k)const
{
Matrix Res(n,m);
for(rint i=0;i<n;++i)
for(rint j=0;j<m;++j)
Res.a[i][j]=(ll)a[i][j]*k%Mod;
return Res;
}
inline Matrix operator*(const Matrix &o)const
{
Matrix Res(n,o.m);
for(rint i=0;i<n;++i)
for(rint k=0;k<m;++k)
for(rint j=0;j<o.m;++j)
Res.a[i][j]=Add(Res.a[i][j],(ll)a[i][k]*o.a[k][j]%Mod);
return Res;
}
};
int n,m;
Matrix Sum[1000005],TMul[1000005],TAdd[1000005];
#define Lc (p<<1)
#define Rc (p<<1|1)
#define Mid ((l+r)>>1)
void Build(int p,int l,int r)
{
Sum[p].Init(1,3),TMul[p].Init(3,3),TAdd[p].Init(1,3),TMul[p].IOne();
if(l==r){for(rint i=0;i<3;++i)Sum[p].a[0][i]=Getint();return;}
Build(Lc,l,Mid),Build(Rc,Mid+1,r),Sum[p]=Sum[Lc]+Sum[Rc];
}
inline void Pushdown(int p,int l,int r)
{
TMul[Lc]=TMul[Lc]*TMul[p];
TMul[Rc]=TMul[Rc]*TMul[p];
TAdd[Lc]=TAdd[Lc]*TMul[p]+TAdd[p];
TAdd[Rc]=TAdd[Rc]*TMul[p]+TAdd[p];
Sum[Lc]=Sum[Lc]*TMul[p]+TAdd[p]*(Mid-l+1);
Sum[Rc]=Sum[Rc]*TMul[p]+TAdd[p]*(r-Mid);
TMul[p].Clear(),TAdd[p].Clear(),TMul[p].IOne();
}
inline void Modify(int p,int l,int r,int tl,int tr,const Matrix &o,int t)//t=0 Mul t=1 Add
{
if(tl<=l&&r<=tr)
{
if(!t)TMul[p]=TMul[p]*o,TAdd[p]=TAdd[p]*o,Sum[p]=Sum[p]*o;
else TAdd[p]=TAdd[p]+o,Sum[p]=Sum[p]+o*(r-l+1);
return;
}
Pushdown(p,l,r);
if(tl<=Mid)Modify(Lc,l,Mid,tl,tr,o,t);
if(tr>Mid)Modify(Rc,Mid+1,r,tl,tr,o,t);
Sum[p]=Sum[Lc]+Sum[Rc];
}
inline Matrix Query(int p,int l,int r,int tl,int tr)
{
if(tl<=l&&r<=tr)return Sum[p];
Pushdown(p,l,r);
Matrix Res(1,3);
if(tl<=Mid)Res=Query(Lc,l,Mid,tl,tr);
if(tr>Mid)Res=Res+Query(Rc,Mid+1,r,tl,tr);
return Res;
}
int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
Build(1,1,n=Getint()),m=Getint();
Matrix M1(3,3),M2(3,3),M3(3,3),A4(1,3),M5(3,3),M6(3,3),A6(1,3),Res;
M1.a[0][0]=1,M1.a[1][0]=1,M1.a[1][1]=1,M1.a[2][2]=1;
M2.a[0][0]=1,M2.a[1][1]=1,M2.a[2][1]=1,M2.a[2][2]=1;
M3.a[0][0]=1,M3.a[0][2]=1,M3.a[1][1]=1,M3.a[2][2]=1;
M5.a[0][0]=1,M5.a[2][2]=1,M6.a[0][0]=1,M6.a[1][1]=1;
for(rint op,l,r;m--;)
{
op=Getint(),l=Getint(),r=Getint();
if(op==1)Modify(1,1,n,l,r,M1,0);
else if(op==2)Modify(1,1,n,l,r,M2,0);
else if(op==3)Modify(1,1,n,l,r,M3,0);
else if(op==4)A4.a[0][0]=Getint(),Modify(1,1,n,l,r,A4,1);
else if(op==5)M5.a[1][1]=Getint(),Modify(1,1,n,l,r,M5,0);
else if(op==6)A6.a[0][2]=Getint(),Modify(1,1,n,l,r,M6,0),Modify(1,1,n,l,r,A6,1);
else Res=Query(1,1,n,l,r),Putint(Res.a[0][0],' '),Putint(Res.a[0][1],' '),Putint(Res.a[0][2],'\n');
}
return fwrite(Out,1,Outp-Out,stdout),0;
}