Description

大魔法师小 L 制作了 \(n\) 个魔力水晶球,每个水晶球有水、火、土三个属性的能量值。小 L 把这 \(n\) 个水晶球在地上从前向后排成一行,然后开始今天的魔法表演。

我们用 \(A_i,B_i,C_i\) 分别表示从前向后第 \(i\) 个水晶球(下标从 \(1\) 开始)的水、火、土的能量值。

小 L 计划施展 \(m\) 次魔法。每次,他会选择一个区间 \([l,r]\),然后施展以下 \(3\) 大类、\(7\) 种魔法之一:

1. 魔力激发:令区间里每个水晶球中特定属性的能量爆发,从而使另一个特定属性的能量增强。具体来说,有以下三种可能的表现形式:

  • 土元素激发火元素能量:令 \(A_i=A_i+B_i\)。
  • 水元素激发土元素能量:令 \(B_i=B_i+C_i\)。
  • 火元素激发水元素能量:令 \(C_i=C_i+A_i\)。

需要注意的是,增强一种属性的能量并不会改变另一种属性的能量,例如 \(A_i+B_i\) 并不会使 \(B_i\) 增加或减少。

2. 魔力增强:小 L 挥舞法杖,消耗自身 \(v\) 点法力值,来改变区间里每个水晶球的特定属性的能量。具体来说,有以下三种可能的表现形式:

  • 火元素能量定值增强:令 \(A_i=A_i+v\)。
  • 水元素能量翻倍增强:令 \(B_i=B_i\cdot v\)。
  • 土元素能量吸收融合:令 \(C_i=v\)。

3. 魔力释放:小 L 将区间里所有水晶球的能量聚集在一起,融合成一个新的水晶球,然后送给场外观众。生成的水晶球每种属性的能量值等于区间内所有水晶球对应能量值的代数和。需要注意的是,魔力释放的过程不会真正改变区间内水晶球的能量。

值得一提的是,小 L 制造和融合的水晶球的原材料都是定制版的 OI 工厂水晶,所以这些水晶球有一个能量阈值 \(998244353\)。当水晶球中某种属性的能量值大于等于这个阈值时,能量值会自动对阈值取模,从而避免水晶球爆炸。

小 W 为小 L(唯一的)观众,围观了整个表演,并且收到了小 L 在表演中融合的每个水晶球。小 W 想知道,这些水晶球蕴涵的三种属性的能量值分别是多少。

题目大意

给定一个长度为 \(n\) 的序列,每个位置有 \(A_i,B_i,C_i\) 三种权值。

有 \(m\) 次操作,分别可能是区间 \(A_i=A_i+B_i\)、\(B_i=B_i+C_i\)、\(C_i=C_i+A_i\)、\(A_i=A_i+v\)、\(B_i=B_i\cdot v\)、\(C_i=v\)。其中 \(v\) 是每次给定的常数。也可能是询问区间 \(A_i,B_i,C_i\) 分别的和。答案对 \(998244353\) 取模。\(n,m\leq 2.5\times 10^5\)。

Solution

考虑用矩阵维护这些操作。

操作一 \(A_i=A_i+B_i\) 的转移:

\(\begin{bmatrix}A&B&C&1\end{bmatrix}\times \begin{bmatrix}1&0&0&0\\1&1&0&0\\0&0&1&0\\0&0&0&1\end{bmatrix}=\begin{bmatrix}A+B&B&C&1\end{bmatrix}\)

操作二 \(B_i=B_i+C_i\) 的转移:

\(\begin{bmatrix}A&B&C&1\end{bmatrix}\times \begin{bmatrix}1&0&0&0\\0&1&0&0\\0&1&1&0\\0&0&0&1\end{bmatrix}=\begin{bmatrix}A&B+C&C&1\end{bmatrix}\)

操作三 \(C_i=C_i+A_i\) 的转移:

\(\begin{bmatrix}A&B&C&1\end{bmatrix}\times \begin{bmatrix}1&0&1&0\\0&1&0&0\\0&0&1&0\\0&0&0&1\end{bmatrix}=\begin{bmatrix}A&B&C+A&1\end{bmatrix}\)

操作四 \(A_i=A_i+v\) 的转移:

\(\begin{bmatrix}A&B&C&1\end{bmatrix}\times \begin{bmatrix}1&0&0&0\\0&1&0&0\\0&0&1&0\\v&0&0&1\end{bmatrix}=\begin{bmatrix}A+v&B&C&1\end{bmatrix}\)

操作五 \(B_i=B_i\cdot v\) 的转移:

\(\begin{bmatrix}A&B&C&1\end{bmatrix}\times \begin{bmatrix}1&0&0&0\\0&v&0&0\\0&0&1&0\\0&0&0&1\end{bmatrix}=\begin{bmatrix}A&B\cdot v&C&1\end{bmatrix}\)

操作六 \(C_i=v\) 的转移:

\(\begin{bmatrix}A&B&C&1\end{bmatrix}\times \begin{bmatrix}1&0&0&0\\0&1&0&0\\0&0&0&0\\0&0&v&1\end{bmatrix}=\begin{bmatrix}A&B&v&1\end{bmatrix}\)

由于矩阵的结合律和分配律成立,单点修改可以自然地推广到区间,即推出矩阵后直接用线段树维护区间矩阵乘积即可。

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10,mod=998244353;
int n,q,opt,l,r,v,ans[4];
struct data{
int a[4][4];
}f,sum[N<<2],tag[N<<2];
void mul(data &x,data &y){ //矩阵乘法
int c[4][4];
memset(c,0,sizeof(c));
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
for(int k=0;k<4;k++)
c[i][j]=(c[i][j]+1ll*x.a[i][k]*y.a[k][j])%mod;
memcpy(x.a,c,sizeof(c));
}
void pushup(int p){
for(int i=0;i<4;i++)
sum[p].a[0][i]=(sum[p<<1].a[0][i]+sum[p<<1|1].a[0][i])%mod;
}
void pushdown(int p){
bool flag=1;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(tag[p].a[i][j]!=f.a[i][j]) flag=0; //非单位矩阵,则 flag=0
if(flag) return ;
mul(sum[p<<1],tag[p]),mul(tag[p<<1],tag[p]);
mul(sum[p<<1|1],tag[p]),mul(tag[p<<1|1],tag[p]);
tag[p]=f;
}
void build(int p,int l,int r){
sum[p].a[0][3]=r-l+1,tag[p]=f;
if(l==r){for(int i=0;i<3;i++) scanf("%d",&sum[p].a[0][i]);return ;}
int mid=(l+r)/2;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void modify(int p,int l,int r,int lx,int rx,data v){
if(l>=lx&&r<=rx){mul(sum[p],v),mul(tag[p],v);return ;}
int mid=(l+r)/2;
pushdown(p);
if(lx<=mid) modify(p<<1,l,mid,lx,rx,v);
if(rx>mid) modify(p<<1|1,mid+1,r,lx,rx,v);
pushup(p);
}
void query(int p,int l,int r,int lx,int rx){
if(l>=lx&&r<=rx){
for(int i=0;i<3;i++)
ans[i]=(ans[i]+sum[p].a[0][i])%mod;
return ;
}
int mid=(l+r)/2;
pushdown(p);
if(lx<=mid) query(p<<1,l,mid,lx,rx);
if(rx>mid) query(p<<1|1,mid+1,r,lx,rx);
pushup(p);
}
signed main(){
for(int i=0;i<4;i++) f.a[i][i]=1; //单位矩阵
scanf("%d",&n),build(1,1,n),scanf("%d",&q);
while(q--){
scanf("%d%d%d",&opt,&l,&r);
if(opt<=6){
data tmp=f;
if(opt==1) tmp.a[1][0]=1;
else if(opt==2) tmp.a[2][1]=1;
else if(opt==3) tmp.a[0][2]=1;
else if(opt==4) scanf("%d",&v),tmp.a[3][0]=v;
else if(opt==5) scanf("%d",&v),tmp.a[1][1]=v;
else scanf("%d",&v),tmp.a[2][2]=0,tmp.a[3][2]=v;
modify(1,1,n,l,r,tmp); //tmp: 转移矩阵
}
else{
memset(ans,0,sizeof(ans)),query(1,1,n,l,r);
for(int i=0;i<3;i++)
printf("%d%c",ans[i],i==2?'\n':' ');
}
}
return 0;
}

「THUSCH 2017」大魔法师的更多相关文章

  1. 「THUSCH 2017」大魔法师 解题报告

    「THUSCH 2017」大魔法师 狗体面太长,帖链接了 思路,维护一个\(1\times 4\)的答案向量表示\(A,B,C,len\),最后一个表示线段树上区间长度,然后每次的操作都有一个转移矩阵 ...

  2. LOJ 2980 「THUSCH 2017」大魔法师——线段树

    题目:https://loj.ac/problem/2980 线段树维护矩阵. 然后是 30 分.似乎是被卡常了?…… #include<cstdio> #include<cstri ...

  3. @loj - 2977@ 「THUSCH 2017」巧克力

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 「人生就像一盒巧克力,你永远不知道吃到的下一块是什么味道.」 明 ...

  4. LOJ #2978「THUSCH 2017」杜老师

    听说LOJ传了THUSC题赶紧上去看一波 随便点了一题都不会做想了好久才会写暴力爆了一发过了... LOJ #2978 题意 $ T$次询问,每次询问$ L,R$,问有多少种选取区间中数的方案使得选出 ...

  5. loj#2978. 「THUSCH 2017」杜老师(乱搞)

    题面 传送门 题解 感谢yx巨巨 如果一个数是完全平方数,那么它的所有质因子个数都是偶数 我们把每一个数分别维护它的每一个质因子的奇偶性,那么就是要我们选出若干个数使得所有质因子的个数为偶数.如果用线 ...

  6. LOJ#2977. 「THUSCH 2017」巧克力(斯坦纳树+随机化)

    题目 题目 做法 考虑部分数据(颜色较少)的: 二分中位数\(mid\),将\(v[i]=1000+(v[i]>mid)\) 具体二分操作:然后求出包含\(K\)种颜色的联通快最小的权值和,判断 ...

  7. LOJ 2979 「THUSCH 2017」换桌——多路增广费用流

    题目:https://loj.ac/problem/2979 原来的思路: 优化连边.一看就是同一个桌子相邻座位之间连边.相邻桌子对应座位之间连边. 每个座位向它所属的桌子连边.然后每个人建一个点,向 ...

  8. LOJ 2978 「THUSCH 2017」杜老师——bitset+线性基+结论

    题目:https://loj.ac/problem/2978 题解:https://www.cnblogs.com/Paul-Guderian/p/10248782.html 第 i 个数的 bits ...

  9. LOJ 2997 「THUSCH 2017」巧克力——思路+随机化+斯坦纳树

    题目:https://loj.ac/problem/2977 想到斯坦纳树.但以为只能做 “包含一些点” 而不是 “包含一些颜色” .而且不太会处理中位数. 其实 “包含一些颜色” 用斯坦纳树做也和普 ...

随机推荐

  1. cvc-complex-type.2.3: Element 'servlet' cannot have character [children], because the type's content

    错误原因:粘贴代码 <servlet> <servlet-name>barServlet</servlet-name> <servlet-class>S ...

  2. acute

    In Euclidean geometry, an angle is the figure formed by two rays, called the sides of the angle, sha ...

  3. Scala(六)【模式匹配】

    目录 一.基本语法 二.匹配固定值 三.守卫 四.匹配类型 五.匹配集合 1.Array 2.List 3.元祖 4.对象和样例类 六.偏函数 七.赋值匹配 八.for循环匹配 一.基本语法 在匹配某 ...

  4. 30个类手写Spring核心原理之环境准备(1)

    本文节选自<Spring 5核心原理> 1 IDEA集成Lombok插件 1.1 安装插件 IntelliJ IDEA是一款非常优秀的集成开发工具,功能强大,而且插件众多.Lombok是开 ...

  5. Linux学习 - 目录表

    目录名 作用 权限 说明 /bin/ 存放系统命令的目录 所有用户 存放在/bin/下的命令单用户模式下也可以执行 /sbin/ 保存和系统环境设置相关的命令 root                 ...

  6. Oracle存储过程游标for循环怎么写

    一.不带参数的游标for循环 首先编写存储过程的整体结构,如下: create or replace procedure test_proc is v_date date; --变量定义 begin ...

  7. JavaEE复习三

    Http协议是基于请求/响应模式.无状态的协议:所有请求时相互独立的.无连续的:服务器无法记住与识别用户. 对于简单的页面浏览或信息获取,http协议可以完全胜任:对于需要提供客户端和服务器端交互的网 ...

  8. 【Matlab】线性调频信号LFM 仿真

    [知识点] 生成序列 i = a:step:b 举例: i = 1:1:9 画图(子图) subplot(m,n,p)或者subplot(m n p) 总结起来就是,画一个m行n列的图. p表示在第p ...

  9. 华为云函数中使用云数据库的JavaScript SDK基础入门

    背景介绍 使用云数据库Server端的SDK,此处我以华为提供的官方Demo为例,他们的Demo也已经开源放在了GitHub上,大家需要的可以自行下载. https://github.com/AppG ...

  10. Mysql脚本 生成测试数据

    使用: ./xie.sh -uroot -p'123456' #!/bin/bash #混合测试数据库脚本 #将创建一个single数据库,其中创建一个s1表 #如果数据库存在,将会写入数据,可以在写 ...