大魔法师
题解
有一道线段树水题。
好吧,看到每一个操作,惊奇地发现这几个操作矩阵都可以解决,而题目又要求更改一个区间,所以用线段树来维护。
我们可以将树上的每一个点建成一个1*4的矩阵,第一二三个点分别记录a,b,c的值,而第四个记录区间的大小。合并时将两个子区间相加即可。
进行更改时的矩阵构造也很简单,前面的相加很好想,分别是。
而后面的与v有关的几个操作也很明显,分别为。
之后加个懒标记就可以了,具体操作也很简单。
源码
%: pragma GCC optimize(3)
//%: pragma GCC optimize(2)
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
#define MAXN 250000
typedef long long LL;
const int mo=998244353;
#define gc() getchar()
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=gc();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
x*=f;
}
inline int add(int a,int b){return a+b>mo?a+b-mo:a+b;}
struct ming{
int c[5][5],n,m;
ming(){n=m=0;memset(c,0,sizeof(c));}
ming operator * (const ming& b){
ming r;r.n=n;r.m=b.m;
for(int i=1;i<=r.n;++i)
for(int j=1;j<=m;++j)
if(c[i][j])
for(int k=1;k<=r.m;++k)
r.c[i][k]=add(r.c[i][k],1ll*c[i][j]*b.c[j][k]%mo);
return r;
}
ming operator + (const ming& b){
ming r;r.n=n;r.m=m;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
r.c[i][j]=add(c[i][j],b.c[i][j]);
return r;
}
void clear(){memset(c,0,sizeof(c));n=m=0;}
void init(){n=m=4;for(int i=1;i<=n;++i)c[i][i]=1;}
bool empty(){
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
if(i==j&&c[i][j]!=1)return false;
if(i!=j&&c[i][j]!=0)return false;
}
return true;
}
}B[MAXN<<2],lzy[MAXN<<2];
int n,m,a[MAXN],b[MAXN],c[MAXN];
void build(int rt,int l,int r){
if(l>r)return ;
if(l==r){
B[rt].n=1;B[rt].m=4;
B[rt].c[1][1]=a[l];
B[rt].c[1][2]=b[l];
B[rt].c[1][3]=c[l];
B[rt].c[1][4]=1;
lzy[rt].init();
//printf("build%d %d %d\n",rt,l,r);B[rt].print();
//puts("\n\n");
return ;
}
int mid=l+r>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
B[rt]=B[rt<<1]+B[rt<<1|1];lzy[rt].init();
//printf("build%d %d %d\n",rt,l,r);B[rt].print();
//puts("\n\n");
}
void pushdown(int rt){
if(lzy[rt].empty())return ;
B[rt<<1]=B[rt<<1]*lzy[rt];
B[rt<<1|1]=B[rt<<1|1]*lzy[rt];
lzy[rt<<1]=lzy[rt<<1]*lzy[rt];
lzy[rt<<1|1]=lzy[rt<<1|1]*lzy[rt];
lzy[rt].clear();lzy[rt].init();
}
void insert(int rt,int l,int r,int al,int ar,ming aw){
if(l>r||l>ar||r<al)return ;
//printf("%d %d %d %d\n",l,r,al,ar);
if(al<=l&&r<=ar){
//B[rt].print();
B[rt]=B[rt]*aw;lzy[rt]=lzy[rt]*aw;
//printf("insert%d %d %d\n",rt,l,r);B[rt].print();
//puts("\n\n");
return ;
}
int mid=l+r>>1;pushdown(rt);
insert(rt<<1,l,mid,al,ar,aw);
insert(rt<<1|1,mid+1,r,al,ar,aw);
B[rt]=B[rt<<1]+B[rt<<1|1];
//printf("insert%d %d %d\n",rt,l,r);B[rt].print();
//puts("\n\n");
}
ming query(int rt,int l,int r,int al,int ar){
ming res;res.n=1;res.m=4;
if(l>r||l>ar||r<al)return res;
if(al<=l&&r<=ar)return B[rt];
int mid=l+r>>1;pushdown(rt);
res=query(rt<<1,l,mid,al,ar)+query(rt<<1|1,mid+1,r,al,ar);
return res;
}
ming A1,A2,A3,A4,A5,A6;
signed main(){
//freopen("2.in","r",stdin);
//freopen("3.out","w",stdout);
read(n);
for(int i=1;i<=n;++i)read(a[i]),read(b[i]),read(c[i]);
build(1,1,n);read(m);
A1.init();A1.c[2][1]=1;
A2.init();A2.c[3][2]=1;
A3.init();A3.c[1][3]=1;
A4.init();A5.init();
A6.init();A6.c[3][3]=0;
for(int i=1;i<=m;++i){
int opt;read(opt);
if(opt==1){
int l,r;read(l);read(r);
//printf("111a%d %d\n",l,r);
insert(1,1,n,l,r,A1);
}
if(opt==2){
int l,r;read(l);read(r);
insert(1,1,n,l,r,A2);
}
if(opt==3){
int l,r;read(l);read(r);
insert(1,1,n,l,r,A3);
}
if(opt==4){
int l,r,v;read(l);read(r);read(v);
A4.c[4][1]=v;insert(1,1,n,l,r,A4);
}
if(opt==5){
int l,r,v;read(l);read(r);read(v);
A5.c[2][2]=v;insert(1,1,n,l,r,A5);
}
if(opt==6){
int l,r,v;read(l);read(r);read(v);
A6.c[4][3]=v;insert(1,1,n,l,r,A6);
}
if(opt==7){
int l,r;read(l);read(r);
ming C=query(1,1,n,l,r);
printf("%d %d %d\n",C.c[1][1],C.c[1][2],C.c[1][3]);
}
}
return 0;
}