• 【洛谷7453】[THUSCH2017] 大魔*(线段树+矩乘)


    点此看题面

    • (n)个水晶球,第(i)个水晶球有三个属性(A_i,B_i,C_i)
    • (q)次区间操作,分为七种:将(A_i)加上(B_i);将(B_i)加上(C_i);将(C_i)加上(A_i);将(A_i)加上(v);将(B_i)乘上(v);将(C_i)修改为(v);求三种属性各自的和。
    • (n,qle2.5 imes10^5)

    线段树+矩阵乘法

    一个挺有意思的技巧。

    考虑我们初始在每个点维护一个矩阵:

    [egin{bmatrix} a_i&0&0&0\ 0&b_i&0&0\ 0&0&c_i&0\ 0&0&0&1 end{bmatrix} ]

    然后发现这些操作都是矩乘基本操作,只要给线段树上一段区间同时乘上一个矩阵即可。

    下面分别给出每种操作对应的矩阵:

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

    询问就是在线段树上区间求和,然后输出每列数的和即可。

    代码:(O(64nlogn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 250000
    #define X 998244353
    using namespace std;
    int n,a[N+5],b[N+5],c[N+5];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void write(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);}
    	Tp I void writeln(Con Ty& x,Con Ty& y,Con Ty& z) {write(x),pc(' '),write(y),pc(' '),write(z),pc('
    ');}
    }using namespace FastIO;
    struct M
    {
    	int a[4][4];I M(CI x=0) {memset(a,0,sizeof(a));for(RI i=0;i^4;++i) a[i][i]=x;}
    	I Con int* operator [] (CI x) Con {return a[x];}I int* operator [] (CI x) {return a[x];}
    	I M operator + (Con M& o) Con {M t;for(RI i=0;i^4;++i) for(RI j=0;j^4;++j) t[i][j]=(a[i][j]+o[i][j])%X;return t;}//矩阵加法
    	I M operator * (Con M& o) Con {M t;for(RI i=0;i^4;++i)//矩阵乘法
    		for(RI j=0;j^4;++j) for(RI k=0;k^4;++k) t[i][j]=(t[i][j]+1LL*a[i][k]*o[k][j])%X;return t;}
    	I bool Ex() {for(RI i=0;i^4;++i) for(RI j=0;j^4;++j) if(a[i][j]^(i==j)) return 1;return 0;}//判断是不是单位矩阵
    };
    class SegmentTree
    {
    	private:
    		#define PT CI l=1,CI r=n,CI rt=1
    		#define LT l,mid,rt<<1
    		#define RT mid+1,r,rt<<1|1
    		#define PU(x) (V[x]=V[x<<1]+V[x<<1|1])
    		#define PD(x) (F[x].Ex()&&(T(x<<1,F[x]),T(x<<1|1,F[x]),F[x]=M(1),0))
    		#define T(x,v) (V[x]=V[x]*v,F[x]=F[x]*v)
    		M V[N<<2],F[N<<2];
    	public:
    		I void Bd(PT)//建树
    		{
    			if(F[rt]=M(1),l==r) return (void)(V[rt][0][0]=a[l],V[rt][1][1]=b[l],V[rt][2][2]=c[l],V[rt][3][3]=1);
    			RI mid=l+r>>1;Bd(LT),Bd(RT),PU(rt);
    		}
    		I void U(CI L,CI R,Con M& v,PT)//区间乘法
    		{
    			if(L<=l&&r<=R) return (void)T(rt,v);RI mid=l+r>>1;PD(rt);
    			L<=mid&&(U(L,R,v,LT),0),R>mid&&(U(L,R,v,RT),0),PU(rt); 
    		}
    		I M Q(CI L,CI R,PT)//区间求和
    		{
    			if(L==l&&r==R) return V[rt];RI mid=l+r>>1;PD(rt);
    			if(R<=mid) return Q(L,R,LT);if(L>mid) return Q(L,R,RT);return Q(L,mid,LT)+Q(mid+1,R,RT);
    		}
    }S;
    int main()
    {
    	RI Qt,i;for(read(n),i=1;i<=n;++i) read(a[i],b[i],c[i]);S.Bd();
    	RI op,x,y,v;M t;read(Qt);W(Qt--) switch(read(op,x,y),op)//对每种修改分别构造矩阵
    	{
    		case 1:(t=M(1))[1][0]=1,S.U(x,y,t);break;
    		case 2:(t=M(1))[2][1]=1,S.U(x,y,t);break;
    		case 3:(t=M(1))[0][2]=1,S.U(x,y,t);break;
    		case 4:read(v),(t=M(1))[3][0]=v,S.U(x,y,t);break;
    		case 5:read(v),(t=M(1))[1][1]=v,S.U(x,y,t);break;
    		case 6:read(v),(t=M(1))[3][2]=v,t[2][2]=0,S.U(x,y,t);break;
    		case 7:t=S.Q(x,y),writeln((0LL+t[0][0]+t[1][0]+t[2][0]+t[3][0])%X,
    			(0LL+t[0][1]+t[1][1]+t[2][1]+t[3][1])%X,(0LL+t[0][2]+t[1][2]+t[2][2]+t[3][2])%X);break;//输出每一列的和
    	}return clear(),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    【Vue前端】Vue前端注册业务实现!!!【代码】
    QQ第三方登录逻辑(微信,微博等同)
    发送短信验证码逻辑
    web图形验证码逻辑
    PID算法资料【视频+PDF介绍】
    如何配置电脑本地的域名
    js实现阻止默认事件preventDefault与returnValue
    js实现事件监听与阻止监听传播
    json字符串转换对象的方法1
    json字符串转换对象的方法
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu7453.html
Copyright © 2020-2023  润新知