• THUSCH 2017 大魔*(矩阵乘法+线段树)


    题意

    https://loj.ac/problem/2980

    思路

    区间修改考虑用线段树维护。由于一段区间的 (A,B,C) 可以表示成由原来的 (A,B,C) 乘上带上系数再加上某一个某个常数,不妨用矩阵来形象的表示这个转移。

    在线段树的每一个节点上,用一个 (1 imes 3) 的矩阵 (egin{pmatrix}A &B&Cend{pmatrix}) 表示这个区间的 (A,B,C) 之和。用一个 (3 imes 3) 的矩阵代表一个矩阵乘法的懒惰标记,用一个 (1 imes 3) 的矩阵代表一次矩阵加法的懒惰标记。

    操作一 (Aleftarrow A+B)

    相当乘上于一个这样的矩阵

    [egin{pmatrix} 1&0&0\ 1&1&0\ 0&0&1 end{pmatrix} ]

    操作二 (Bleftarrow B+C)

    相当于乘上一个这样的矩阵

    [egin{pmatrix} 1&0&0\ 0&1&0\ 0&1&1 end{pmatrix} ]

    操作三 (Cleftarrow C+A)

    相当于乘上一个这样的矩阵

    [egin{pmatrix} 1&0&1\ 0&1&0\ 0&0&1 end{pmatrix} ]

    操作四 (Aleftarrow A+v)

    相当于加上一个这样的矩阵

    [egin{pmatrix} v\ 0\ 0 end{pmatrix} ]

    操作五 (Bleftarrow B cdot v)

    相当于乘上一个这样的矩阵

    [egin{pmatrix} 1&0&0\ 0&v&0\ 0&0&1 end{pmatrix} ]

    操作六 (C leftarrow v)

    相当于乘上一个全零的 (3 imes 3) 矩阵,再加上一个这样的矩阵

    [egin{pmatrix} 0\ 0\ v end{pmatrix} ]

    注意再作加法时,将总和矩阵与加标记矩阵做一次矩阵加法(总和矩阵需要乘上区间长度,与维护普通整数的线段树类似),作乘法时需要将总和矩阵、加标记矩阵、乘标记矩阵都做一次矩阵乘法。要注意利用封装使得和线段树的看起来和区间加值、区间乘值、区间求和的线段树没有区别,自然就能写好。

    代码

    #include<bits/stdc++.h>
    #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
    #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
    template<typename T,typename _T>inline bool chk_min(T &x,const _T y){return y<x?x=y,1:0;}
    template<typename T,typename _T>inline bool chk_max(T &x,const _T y){return x<y?x=y,1:0;}
    typedef long long ll;
    const int N=2.5e5+5;
    const int P=998244353;
    struct Matrix
    {
    	int n,m;
    	int a[3][3];
    	void resize(int _n,int _m){n=_n,m=_m;}
    	int *operator [](const int x){return a[x-1]-1;}
    	Matrix operator +(const Matrix &_)const
    	{
    		Matrix res;
    		res.resize(n,m);
    		FOR(i,1,n)FOR(j,1,m)res[i][j]=(a[i-1][j-1]+_.a[i-1][j-1])%P;
    		return res;
    	}
    	Matrix operator *(const Matrix &_)const
    	{
    		Matrix res;
    		res.resize(n,_.m);
    		FOR(i,1,n)FOR(j,1,_.m)
    		{
    			res[i][j]=0;
    			FOR(k,1,m)res[i][j]=(res[i][j]+(ll)a[i-1][k-1]*_.a[k-1][j-1])%P;
    		}
    		return res;
    	}
    	Matrix operator *(const int &x)const
    	{
    		Matrix res;
    		res.resize(n,m);
    		FOR(i,1,n)FOR(j,1,m)res[i][j]=(ll)a[i-1][j-1]*x%P;
    		return res;
    	}
    };
    Matrix sum[N<<2],mul[N<<2],pls[N<<2];
    void multiplied(int k,Matrix &x)
    {
    	sum[k]=sum[k]*x;
    	mul[k]=mul[k]*x;
    	pls[k]=pls[k]*x;
    }
    void plused(int k,Matrix &x,int l,int r)
    {
    	sum[k]=sum[k]+x*(r-l+1);
    	pls[k]=pls[k]+x;
    }
    void push_up(int k)
    {
    	sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    void push_down(int k,int l,int r)
    {
    	bool m=0,p=0;
    	FOR(i,1,3)FOR(j,1,3)if(mul[k][i][j]!=(i==j)){m=1;break;}
    	FOR(i,1,3)if(pls[k][1][i]){p=1;break;}
    	int mid=(l+r)>>1;
    	if(m)
    	{
    		multiplied(k<<1,mul[k]);
    		multiplied(k<<1|1,mul[k]);
    		FOR(i,1,3)FOR(j,1,3)mul[k][i][j]=(i==j);
    	}
    	if(p)
    	{
    		plused(k<<1,pls[k],l,mid);
    		plused(k<<1|1,pls[k],mid+1,r);
    		FOR(i,1,3)pls[k][1][i]=0;
    	}
    }
    void build(int k,int l,int r)
    {
    	sum[k].resize(1,3),mul[k].resize(3,3),pls[k].resize(1,3);
    	FOR(i,1,3)pls[k][1][i]=0;
    	FOR(i,1,3)FOR(j,1,3)mul[k][i][j]=(i==j);
    	if(l==r)
    	{
    		scanf("%d%d%d",&sum[k][1][1],&sum[k][1][2],&sum[k][1][3]);
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
    	push_up(k);
    }
    void update_mul(int k,int L,int R,Matrix &x,int l,int r)
    {
    	if(L<=l&&r<=R)
    	{
    		multiplied(k,x);
    		return;
    	}
    	push_down(k,l,r);
    	int mid=(l+r)>>1;
    	if(L<=mid)update_mul(k<<1,L,R,x,l,mid);
    	if(R>mid)update_mul(k<<1|1,L,R,x,mid+1,r);
    	push_up(k);
    }
    void update_pls(int k,int L,int R,Matrix &x,int l,int r)
    {
    	if(L<=l&&r<=R)
    	{
    		plused(k,x,l,r);
    		return;
    	}
    	push_down(k,l,r);
    	int mid=(l+r)>>1;
    	if(L<=mid)update_pls(k<<1,L,R,x,l,mid);
    	if(R>mid)update_pls(k<<1|1,L,R,x,mid+1,r);
    	push_up(k);
    }
    Matrix query(int k,int L,int R,int l,int r)
    {
    	if(L<=l&&r<=R)return sum[k];
    	push_down(k,l,r);
    	int mid=(l+r)>>1;
    	if(R<=mid)return query(k<<1,L,R,l,mid);
    	else if(L>mid)return query(k<<1|1,L,R,mid+1,r);
    	else return query(k<<1,L,R,l,mid)+query(k<<1|1,L,R,mid+1,r);
    }
    int n,m;
    
    int main()
    {
    	scanf("%d",&n);
    	build(1,1,n);
    	scanf("%d",&m);
    	FOR(i,1,m)
    	{
    		Matrix mul,pls;
    		mul.resize(3,3),pls.resize(1,3);
    		int op,l,r,val;
    		scanf("%d%d%d",&op,&l,&r);
    		if(op>=4&&op<=6)scanf("%d",&val);
    		if(op>=1&&op<=3)
    		{
    			FOR(i,1,3)FOR(j,1,3)mul[i][j]=(i==j);
    			if(op==1)mul[2][1]=1;
    			else if(op==2)mul[3][2]=1;
    			else if(op==3)mul[1][3]=1;
    			update_mul(1,l,r,mul,1,n);
    		}
    		else if(op==4)
    		{
    			pls[1][1]=val,pls[1][2]=pls[1][3]=0;
    			update_pls(1,l,r,pls,1,n);
    		}
    		else if(op==5)
    		{
    			FOR(i,1,3)FOR(j,1,3)mul[i][j]=(i==j);
    			mul[2][2]=val;
    			update_mul(1,l,r,mul,1,n);
    		}
    		else if(op==6)
    		{
    			FOR(i,1,3)FOR(j,1,3)mul[i][j]=(i==j);
    			mul[3][3]=0;
    			pls[1][1]=0,pls[1][2]=0,pls[1][3]=val;
    			update_mul(1,l,r,mul,1,n);
    			update_pls(1,l,r,pls,1,n);
    		}
    		else if(op==7)
    		{
    			pls=query(1,l,r,1,n);
    			printf("%d %d %d
    ",pls[1][1],pls[1][2],pls[1][3]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    java web项目打包.war格式
    version 1.4.2-04 of the jvm is not suitable for thi
    Sugarcrm Email Integration
    sharepoint 2010 masterpage中必须的Content PlaceHolder
    微信开放平台
    Plan for caching and performance in SharePoint Server 2013
    使用自定义任务审批字段创建 SharePoint 顺序工作流
    Technical diagrams for SharePoint 2013
    To get TaskID's Integer ID value from the GUID in SharePoint workflow
    how to get sharepoint lookup value
  • 原文地址:https://www.cnblogs.com/Paulliant/p/10570392.html
Copyright © 2020-2023  润新知