0628Zn

一道看着吓人但其实很简单的题

题目描述
给定n个2∗2的下三角矩阵,有下列两种操作:

  1. 对区间(L,R)所有的矩阵逐个相乘。
  2. 对区间(L,R)所有的矩阵左下角的数字增加x。

对每一个操作1,给出答案矩阵。

输入格式
第一行两个整数n,q,表示共n个矩阵,q次询问。
之后2n行,每两行代表一个矩阵。
接下来q行,每行代表一个询问,第一个数字为op,若op为1接下来输入两个数字L,R,若op为2接下来输入三个数字L,R,x,意义如题目描述。

输出格式
对每一个op=1的操作,输出一个2∗2矩阵代表答案。需要对998244353取模。

区间修改,区间查询,显然需要用到线段树,那我们只要考虑怎么合并两个节点就做完这道题了。
首先来看两个矩阵相乘的情况
\(\begin{bmatrix}a_{11}&0\\a_{21}&a_{22}\end{bmatrix}\begin{bmatrix}b_{11}&0\\b_{21}&b_{22}\end{bmatrix}=\begin{bmatrix}a_{11}b_{11}&0\\a_{21}b_{11}+a_{22}b_{21}&a_{22}b_{22}\end{bmatrix}\)
当我们对左下角加上\(x\)
\(\begin{bmatrix}a_{11}&0\\a_{21}+x&a_{22}\end{bmatrix}\begin{bmatrix}b_{11}&0\\b_{21}+x&b_{22}\end{bmatrix}=\begin{bmatrix}a_{11}b_{11}&0\\a_{21}b_{11}+a_{22}b_{21}+x(a_{22}+b_{11})&a_{22}b_{22}\end{bmatrix}\)
我们发现,只有左下角的值发生了改变,并且所有的增量都是\(x\)乘上一个常量系数,那么现在我们的目标就变为了如何处理出它的系数。
显然我们的系数都是存在于左下角,根据矩阵乘法的公式,左乘矩阵的左下角元素会和右乘矩阵的左上角元素相乘,右乘矩阵的左下角元素会和左乘矩阵右下角元素相乘,不难推测出\(sum=a.sum\times b_{11}+a_{22}\times b.sum\)
由于元素的值不一定是数,也可以是代数式,所以上述结论对任意节点都适用。
然后就全都是模板啦

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const long long MOD=998244353;
struct tree{
	long long l,r,a11,a12,a21,a22,sum,add;
}tr[400010];
long long n,q;
void build(long long x,long long l,long long r)
{
	tr[x].l=l,tr[x].r=r;
	if(l==r)
	{
		tr[x].sum=1;
		scanf("%lld %lld",&tr[x].a11,&tr[x].a12);
		scanf("%lld %lld",&tr[x].a21,&tr[x].a22);
		return;
	}
	long long lc=x<<1,rc=lc|1,m=l+r>>1;
	build(lc,l,m);
	build(rc,m+1,r);
	tr[x].sum=(tr[lc].sum*tr[rc].a11%MOD+tr[lc].a22*tr[rc].sum%MOD)%MOD;
	tr[x].a11=tr[lc].a11*tr[rc].a11%MOD;
	tr[x].a22=tr[lc].a22*tr[rc].a22%MOD;
	tr[x].a21=(tr[lc].a21*tr[rc].a11%MOD+tr[lc].a22*tr[rc].a21%MOD)%MOD;
}
void pushdown(long long x)
{
	if(tr[x].add)
	{
		if(tr[x].l!=tr[x].r)
		{
			long long lc=x<<1,rc=lc|1;
			tr[lc].a21=(tr[lc].a21+tr[lc].sum*tr[x].add%MOD)%MOD;
			tr[rc].a21=(tr[rc].a21+tr[rc].sum*tr[x].add%MOD)%MOD;
			tr[lc].add=(tr[lc].add+tr[x].add)%MOD;
			tr[rc].add=(tr[rc].add+tr[x].add)%MOD;
		}
		tr[x].add=0;
	}
}
void change(long long x,long long l,long long r,long long k)
{
	if(tr[x].l>=l&&tr[x].r<=r)
	{
		tr[x].a21=(tr[x].a21+tr[x].sum*k%MOD)%MOD;
		tr[x].add=(tr[x].add+k)%MOD;
		return;
	}
	pushdown(x);
	long long lc=x<<1,rc=lc|1;
	if(l<=tr[lc].r)
		change(lc,l,r,k);
	if(r>=tr[rc].l)
		change(rc,l,r,k);
	tr[x].a21=(tr[lc].a21*tr[rc].a11%MOD+tr[lc].a22*tr[rc].a21%MOD)%MOD;
}
tree query(long long x,long long l,long long r)
{
	if(tr[x].l>=l&&tr[x].r<=r)
		return tr[x];
	pushdown(x);
	tree tmp;
	tmp.a11=tmp.a22=1,tmp.a12=tmp.a21=0;
	long long lc=x<<1,rc=lc|1;
	if(l<=tr[lc].r)
	{
		tree c=query(lc,l,r);
		tmp.a21=(tmp.a21*c.a11%MOD+tmp.a22*c.a21%MOD)%MOD;
		tmp.a11=tmp.a11*c.a11%MOD;
		tmp.a22=tmp.a22*c.a22%MOD;
	}
	if(r>=tr[rc].l)
	{
		tree c=query(rc,l,r);
		tmp.a21=(tmp.a21*c.a11%MOD+tmp.a22*c.a21%MOD)%MOD;
		tmp.a11=tmp.a11*c.a11%MOD;
		tmp.a22=tmp.a22*c.a22%MOD;
	}
	return tmp;
}
int main()
{
	scanf("%lld %lld",&n,&q);
	build(1,1,n);
	while(q--)
	{
		long long opt,l,r;
		scanf("%lld %lld %lld",&opt,&l,&r);
		if(opt&1)
		{
			tree ans=query(1,l,r);
			printf("%lld %lld\n%lld %lld\n",ans.a11,ans.a12,ans.a21,ans.a22);
		}
		else
		{
			long long k;
			scanf("%lld",&k);
			change(1,l,r,k);
		}
	}
	return 0;
}

posted on 2025-08-28 15:39  琬安与璃茗  阅读(6)  评论(0)    收藏  举报