[THUSCH2017] 大魔法师
题目描述
大魔法师小 L 制作了 n n n 个魔力水晶球,每个水晶球有水、火、土三个属性的能量值。小 L 把这 n n n 个水晶球在地上从前向后排成一行,然后开始今天的魔法表演。
我们用 A i , B i , C i A_i,B_i,C_i Ai,Bi,Ci 分别表示从前向后第 i i i 个水晶球(下标从 1 1 1 开始)的水、火、土的能量值。
小 L 计划施展 m m m 次魔法。每次,他会选择一个区间 [ l , r ] [l,r] [l,r],然后施展以下 3 3 3 大类、 7 7 7 种魔法之一:
-
魔力激发:令区间里每个水晶球中特定属性的能量爆发,从而使另一个特定属性的能量增强。具体来说,有以下三种可能的表现形式:
- 火元素激发水元素能量:令 A i = A i + B i A_i=A_i+B_i Ai=Ai+Bi。
- 土元素激发火元素能量:令 B i = B i + C i B_i=B_i+C_i Bi=Bi+Ci。
- 水元素激发土元素能量:令 C i = C i + A i C_i=C_i+A_i Ci=Ci+Ai。
需要注意的是,增强一种属性的能量并不会改变另一种属性的能量,例如 A i = A i + B i A_i=A_i+B_i Ai=Ai+Bi 并不会使 B i B_i Bi 增加或减少。
-
魔力增强:小 L 挥舞法杖,消耗自身 v v v 点法力值,来改变区间里每个水晶球的特定属性的能量。具体来说,有以下三种可能的表现形式:
- 火元素能量定值增强:令 A i = A i + v A_i=A_i+v Ai=Ai+v。
- 水元素能量翻倍增强:令 B i = B i × v B_i=B_i\times v Bi=Bi×v。
- 土元素能量吸收融合:令 C i = v C_i=v Ci=v。
-
魔力释放:小 L 将区间里所有水晶球的能量聚集在一起,融合成一个新的水晶球,然后送给场外观众。生成的水晶球每种属性的能量值等于区间内所有水晶球对应能量值的代数和。需要注意的是,魔力释放的过程不会真正改变区间内水晶球的能量。
值得一提的是,小 L 制造和融合的水晶球的原材料都是定制版的 OI 工厂水晶,所以这些水晶球有一个能量阈值 998244353 998244353 998244353。当水晶球中某种属性的能量值大于等于这个阈值时,能量值会自动对阈值取模,从而避免水晶球爆炸。
小 W 为小 L(唯一的)观众,围观了整个表演,并且收到了小 L 在表演中融合的每个水晶球。小 W 想知道,这些水晶球蕴涵的三种属性的能量值分别是多少。
输入格式
从标准输入读入数据。
我们将上述的 7 7 7 种魔法,从上到下依次标号为 1 ∼ 7 1\sim7 1∼7。
输入的第一行包含一个整数 n n n( 1 ≤ n ≤ 2.5 × 1 0 5 1\le n\le 2.5\times 10^5 1≤n≤2.5×105),表示水晶球个数。
接下来 n n n 行,每行空格隔开的 3 3 3 个整数,其中第 i i i 行的三个数依次表示 A i , B i , C i A_i,B_i,C_i Ai,Bi,Ci。
接下来一行包含一个整数 m m m( 1 ≤ m ≤ 2.5 × 1 0 5 1\le m\le2.5\times 10^5 1≤m≤2.5×105),表示施展魔法的次数。
接下来
m
m
m 行,每行
3
3
3 或
4
4
4 个数,格式为 opt l r (v)
。其中 opt
表示魔法的编号,
l
,
r
l,r
l,r 表示施展魔法的区间(保证有
l
≤
r
l\le r
l≤r)。特别地,如果施展
4
∼
6
4\sim6
4∼6 号魔法(魔力增强),则还有一个整数
v
v
v,表示小 L 消耗的法力值。
输出格式
输出到标准输出。
对每个
7
7
7 号魔法(魔力释放),输出一行、空格隔开的
3
3
3 个整数 a b c
,分别表示此次融合得到的水晶球的水、火、土元素能量值。
样例 #1
样例输入 #1
2
2 3 3
6 6 6
4
7 1 2
1 1 2
4 1 2 3
7 1 2
样例输出 #1
8 9 9
23 9 9
提示
100 % 100\% 100% 的数据, n , m ≤ 2.5 × 1 0 5 , 0 ≤ A i , B i , C i , v < 998244353 n,m\le2.5\times 10^5,0\le A_i,B_i,C_i,v<998244353 n,m≤2.5×105,0≤Ai,Bi,Ci,v<998244353
- 10 % 10\% 10% 的数据, n × m ≤ 1 0 7 n\times m\le10^7 n×m≤107。
- 另外 10 % 10\% 10% 的数据,每次魔法的区间均为 [ 1 , n ] [1,n] [1,n]。
- 另外 10 % 10\% 10% 的数据,每次非询问魔法的影响区间均为 [ 1 , n ] [1,n] [1,n],所有修改在询问之前。
- 另外 10 % 10\% 10% 的数据, opt ∈ { 4 , 5 , 6 , 7 } \operatorname{opt}\in\{4,5,6,7\} opt∈{4,5,6,7}。
- 另外 15 % 15\% 15% 的数据, opt ∈ { 1 , 2 , 7 } \operatorname{opt}\in\{1,2,7\} opt∈{1,2,7}。
- 另外 15 % 15\% 15% 的数据, opt ∈ { 1 , 2 , 3 , 5 , 7 } \operatorname{opt}\in\{1,2,3,5,7\} opt∈{1,2,3,5,7}。
- 另外 15 % 15\% 15% 的数据, n , m ≤ 1 0 5 n,m\le 10^5 n,m≤105。
- 其他数据,无特殊约定。
样例解释
以下展示每次施展魔法后,两个水晶球内的能量:
(2, 3, 3) (6, 6, 6)
(5, 3, 3) (12, 6, 6)
(8, 3, 3) (15, 6, 6)
(8, 3, 3) (15, 6, 6)
#include<bits/stdc++.h>
#define ls u<<1
#define rs u<<1 | 1
#define mid ((lc[u]+rc[u])>>1)
#define ll long long
using namespace std;
const int sz=4;
const int mod=998244353;
const int maxn=2e5+10+5e4;
struct Mat
{
int mat[sz][sz];
Mat(){memset(mat,0,sizeof mat);}
Mat(int a[sz][sz])
{
for(int i=0;i<sz;i++)
for(int j=0;j<sz;j++) mat[i][j]=a[i][j];
}
Mat operator + (Mat x)
{
Mat ans;
for(int i=0;i<sz;i++)
for(int j=0;j<sz;j++) ans.mat[i][j]=(x.mat[i][j]+mat[i][j])%mod;
return ans;
}
Mat operator * (Mat x)
{
Mat ans;
for(int i=0;i<sz;i++)
for(int k=0;k<sz;k++)
{
int res=mat[i][k];
for(int j=0;j<sz;j++) ans.mat[i][j]=(ll)(ans.mat[i][j]+(ll)x.mat[k][j]*res)%mod;
}
return ans;
}
};
int IOI[sz][sz]={
{1,0,0,0},
{0,1,0,0},
{0,0,1,0},
{0,0,0,1},
};
Mat I(IOI);
Mat a[maxn];
Mat sum[maxn*4],tag[maxn*4];
int lc[maxn*4],rc[maxn*4];
void pushup(int u) {sum[u]=sum[ls]+sum[rs];}
void pushdown(int u)
{
sum[ls]=sum[ls]*tag[u];tag[ls]=tag[ls]*tag[u];
sum[rs]=sum[rs]*tag[u];tag[rs]=tag[rs]*tag[u];
tag[u]=I;
}
void build(int u,int l,int r)
{
//cout<<u<<' '<<l<<' '<<r<<' '<<endl;
lc[u]=l;rc[u]=r;
tag[u]=I;
if(l==r) {sum[u]=a[l];return ;}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,Mat k)
{
if(l<=lc[u] && rc[u]<=r)
{
tag[u]=tag[u]*k;
sum[u]=sum[u]*k;
return ;
}
pushdown(u);
if(l<=mid) modify(ls,l,r,k);
if(mid<r) modify(rs,l,r,k);
pushup(u);
}
Mat getsum(int u,int l,int r)
{
if(l<=lc[u] && rc[u]<=r)
{
return sum[u];
}
pushdown(u);
Mat res;
if(l<=mid) res=res+getsum(ls,l,r);
if(mid<r) res=res+getsum(rs,l,r);
pushup(u);
return res;
}
int n,m;
void pp()
{
for(int i=1;i<=n;i++)
{
Mat now=getsum(1,i,i);
printf("%d %d %d\n",now.mat[0][0],now.mat[0][1],now.mat[0][2]);
}
cout<<endl;
}
int main()
{
//cout<<"start"<<endl;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i].mat[0][0],&a[i].mat[0][1],&a[i].mat[0][2]);a[i].mat[0][3]=1;
}
//cout<<1<<endl;
scanf("%d",&m);
build(1,1,n);
while(m--)
{
//cout<<m<<endl;
int opt,l,r,v;
scanf("%d%d%d",&opt,&l,&r);
if(opt>=4 && opt<=6) scanf("%d",&v);
Mat data=I;
if(opt==1) data.mat[1][0]=1,modify(1,l,r,data);
if(opt==2) data.mat[2][1]=1,modify(1,l,r,data);
if(opt==3) data.mat[0][2]=1,modify(1,l,r,data);
if(opt==4) data.mat[3][0]=v,modify(1,l,r,data);
if(opt==5) data.mat[1][1]=v,modify(1,l,r,data);
if(opt==6) data.mat[2][2]=0,data.mat[3][2]=v,modify(1,l,r,data);
if(opt==7)
{
Mat now=getsum(1,l,r);
printf("%d %d %d\n",now.mat[0][0],now.mat[0][1],now.mat[0][2]);
}
}//pp();
return 0;
}