逆天卡常题,十几次提交终于过了!
首先看见题目就知道这是道数据结构题,但发现元素之间会有影响,如果直接维护的话无法维护,那么这时矩阵就排上用场了。线段树套矩阵,可以方便地维护一些元素之间有影响的问题。
首先我们每个叶子节点都存放一个矩阵,对于下标 i i i,它的矩阵就是 [ A B C 1 ] \begin{bmatrix} A& B& C&1 \end{bmatrix} [ABC1],因为我们还要考虑 v v v 值的修改。接下来 6 6 6 种操作,我们推出各自对应的矩阵,然后线段树维护区间矩阵乘,维护乘法标记和区间和。这些操作和普通线段树的一样。注意标记初始化为单位矩阵,矩阵乘法没有交换律,注意顺序。
接下来还有卡常部分。
首先矩阵乘法中的循环要展开,然后 pushdown 操作时判断 tag 是否为单位矩阵,若是单位矩阵直接 return,取模时用减法取模,不要全开 long long,这四个是最关键的。
还有一些不那么重要的有如先设一个单位矩阵 I I I,然后初始化时直接等于 I I I 就可以了;线段树的矩阵维护 1 × 4 1\times 4 1×4 的,减少运算量。
最终卡了半天的代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rd read()
const int N=3e5+10,mod=998244353;
namespace IO{
inline int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
template <typename T> inline void write(T x){
if(x>9) write(x/10);
putchar(x%10+'0');
}
}
using namespace IO;
int MOD(int x){return (x>mod)?x-mod:x;}
int n,aa[N],bb[N],cc[N],m;
struct matrix{
int a[4][4];
matrix(){memset(a,0,sizeof(a));}
matrix operator +(const matrix& T)const{
matrix res;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
res.a[i][j]=MOD(1ll*a[i][j]+T.a[i][j]);
return res;
}
matrix operator *(const matrix& T)const{
matrix res;
for(int i=0;i<4;i++){
for(int k=0;k<4;k++){
if(!a[i][k]) continue;
for(int j=0;j<4;j++){
if(!T.a[k][j]) continue;
res.a[i][j]=MOD(res.a[i][j]+1ll*a[i][k]*T.a[k][j]%mod);
}
}
}
return res;
}
bool operator ==(const matrix& T)const{
for(int i=0;i<4;i++) for(int j=0;j<4;j++) if(a[i][j]!=T.a[i][j]) return false;
return true;
}
}A0,B0,C0,A1,B1,C1;
int I_[4][4]={
{1,0,0,0},
{0,1,0,0},
{0,0,1,0},
{0,0,0,1},
};
matrix I;
void Init(){
for(int i=0;i<4;i++) for(int j=0;j<4;j++) I.a[i][j]=I_[i][j];
}
matrix sum[N<<2],tag[N<<2];
void pushdown(int u){
if(tag[u]==I) return;
tag[u<<1]=tag[u<<1]*tag[u],tag[u<<1|1]=tag[u<<1|1]*tag[u];
sum[u<<1]=sum[u<<1]*tag[u],sum[u<<1|1]=sum[u<<1|1]*tag[u];
tag[u]=I;
}
void pushup(int u){
sum[u]=sum[u<<1]+sum[u<<1|1];
}
void build(int u,int l,int r){
tag[u]=I;
if(l==r){sum[u].a[0][0]=aa[l],sum[u].a[0][1]=bb[l],sum[u].a[0][2]=cc[l],sum[u].a[0][3]=1;return;}
int mid=(l+r)>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,int ql,int qr,matrix v){
if(l>=ql&&r<=qr){
tag[u]=tag[u]*v,sum[u]=sum[u]*v;
return;
}
pushdown(u);int mid=(l+r)>>1;
if(ql<=mid) modify(u<<1,l,mid,ql,qr,v);
if(qr>mid) modify(u<<1|1,mid+1,r,ql,qr,v);
pushup(u);
}
matrix query(int u,int l,int r,int ql,int qr){
if(l>=ql&&r<=qr) return sum[u];
pushdown(u);int mid=(l+r)>>1;matrix res;
if(ql<=mid) res=res+query(u<<1,l,mid,ql,qr);
if(qr>mid) res=res+query(u<<1|1,mid+1,r,ql,qr);
return res;
}
void init(){
for(int i=0;i<4;i++){
A0.a[i][i]=A1.a[i][i]=1;
B0.a[i][i]=B1.a[i][i]=1;
C0.a[i][i]=C1.a[i][i]=1;
}
A0.a[1][0]=1,B0.a[2][1]=1,C0.a[0][2]=1,C1.a[2][2]=0;
}
int main(){
n=rd;Init(),init();
for(int i=1;i<=n;i++) aa[i]=rd,bb[i]=rd,cc[i]=rd;
build(1,1,n),m=rd;
while(m--){
int opt=rd,l=rd,r=rd;
if(opt==1) modify(1,1,n,l,r,A0);
else if(opt==2) modify(1,1,n,l,r,B0);
else if(opt==3) modify(1,1,n,l,r,C0);
else if(opt<=6){
int v=rd;
if(opt==4) A1.a[3][0]=v,modify(1,1,n,l,r,A1);
else if(opt==5) B1.a[1][1]=v,modify(1,1,n,l,r,B1);
else C1.a[3][2]=v,modify(1,1,n,l,r,C1);
}
else{
matrix res=query(1,1,n,l,r);
printf("%d %d %d\n",res.a[0][0],res.a[0][1],res.a[0][2]);
}
}
return 0;
}