求助线段树维护矩阵模板题
查看原帖
求助线段树维护矩阵模板题
315205
Kniqht楼主2023/12/15 14:53

rt,调破防了

#include<bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
const int N=1e5+10,mod=1e9+7; 
int n,m,a[N];
struct Matrix{
	ll a[4][4];
	void clear(int x){
		memset(a,x,sizeof(a));
	}
	void init(){// 初始化为对角矩阵 
		a[0][0]=1;a[0][1]=0;
		a[1][0]=0;a[1][1]=1;
	}
}T;
Matrix operator +(const Matrix& A,const Matrix& B){
	Matrix res;res.clear(0);
	for(int i=0;i<=1;i++)
		for(int j=0;j<=1;j++) res.a[i][j]=(A.a[i][j]+B.a[i][j])%mod;
	return res; 
} 
Matrix operator *(const Matrix& A,const Matrix& B){
	Matrix res;res.clear(0);
	for(int i=0;i<=1;i++)
		for(int j=0;j<=1;j++)
			for(int k=0;k<=1;k++)
				res.a[i][j]=(res.a[i][j]+(A.a[i][k]*B.a[k][j])%mod)%mod;
	return res;
}
Matrix operator ^(Matrix A,int p){
	Matrix res;res.init();
	while(p){
		if(p&1) res=res*A;
		A=A*A;p>>=1;
	}
	return res;
}
struct Nd{
	int l,r;
	Matrix sum,add;
}tr[N*2];
void pushup(int u){
	tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
} 
void pushdown(int u){
	Nd &lc=tr[u<<1],&rc=tr[u<<1|1];
	lc.add=lc.add*tr[u].add; // 相当于 a^(b+c)=(a^b)*(a^c) 
	rc.add=rc.add*tr[u].add;
	lc.sum=lc.sum*tr[u].add;
	rc.sum=rc.sum*tr[u].add;
	tr[u].add.init(); 
	// 矩阵乘法满足分配律,但是只有在对角矩阵的时候才满足交换律 
}
void build(int u,int l,int r){
	tr[u]={l,r};
	tr[u].add.init();
	if(l==r){
		if(a[l]==1) tr[u].sum.a[0][0]=1;
		else tr[u].sum.a[0][0]=tr[u].sum.a[0][1]=1;
		if(a[l]>2) tr[u].sum=tr[u].sum*(T^(a[l]-2));
		return;
	}
	int mid=l+r>>1;
	build(u<<1,l,mid);build(u<<1|1,mid+1,r);
	pushup(u);
}
void modify(int u,int l,int r,Matrix v){
	if(tr[u].l>r||tr[u].r<l) return;
	if(tr[u].l>=l&&tr[u].r<=r){
		tr[u].add=tr[u].add*v;
		tr[u].sum=tr[u].sum*v;
		return;
	}
	pushdown(u);
	modify(u<<1,l,r,v);modify(u<<1|1,l,r,v);
	pushup(u); 
}
int query(int u,int l,int r){
	if(tr[u].l>r||tr[u].r<l) return 0;
	if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum.a[0][0];
	pushdown(u);
	return (query(u<<1,l,r)+query(u<<1|1,l,r))%mod;
}
signed main(){
    T.a[0][0]=T.a[0][1]=T.a[1][0]=1;
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    build(1,1,n);
    while(m--){
    	int op,l,r,v;
    	scanf("%lld%lld%lld",&op,&l,&r);
    	if(op==1){
    		scanf("%lld",&v);
    		modify(1,l,r,T^v);
		}
		else{
			printf("%lld\n",query(1,l,r)%mod);
		}
	}
	return 0;
}
2023/12/15 14:53
加载中...