CF718C Sasha and Array(线段树+矩阵乘法)
根据斐波那契的性质得出,区间存在结合律,因此我们对于原先给定的先建出线段树,对每个点维护一个矩阵表示当前的斐波那契答案。
对于opt1,就是区间修改,也就是加上一个转移矩阵,传递这个矩阵,与普通的线段树操作一样的
对于opt2.也就是区间查询,查询区间内的和,因此我们只需要维护一个sum矩阵和lazy矩阵即可。
本题设计到的操作都需要进行重载运算符
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=4e5+10; const int mod=1e9+7; struct MA{ ll a[3][3]; MA(){ memset(a,0,sizeof a); } }P,Q,I; struct node{ int l,r; MA sum; MA lazy; }tr[N<<2]; int n,m; int a[N]; void init(){ P.a[0][0]=1,P.a[0][1]=P.a[1][0]=P.a[1][1]=0;//状态矩阵 Q.a[0][0]=Q.a[0][1]=Q.a[1][0]=1,Q.a[1][1]=0;//转移矩阵 I.a[0][0]=I.a[1][1]=1,I.a[1][0]=I.a[0][1]=0;//单位矩阵 } MA operator *(MA a,MA b) { MA tmp; for(int i=0;i<2;i++) { for(int j=0;j<2;j++) { for(int k=0;k<2;k++) { tmp.a[i][j]=((ll)tmp.a[i][j]+(ll)a.a[i][k]*b.a[k][j]%mod)%mod; } } } return tmp; } MA operator+(MA a,MA b){ MA tmp; int i,j; for(i=0;i<2;i++){ for(j=0;j<2;j++) tmp.a[i][j]=(a.a[i][j]+b.a[i][j])%mod; } return tmp; } bool operator !=(MA a,MA b){ int i,j; for(i=0;i<2;i++){ for(j=0;j<2;j++){ if(a.a[i][j]!=b.a[i][j]) return true; } } return false; } MA qpow(MA a,int i) { MA b; for(int i=0;i<2;i++) b.a[i][i]=1; while(i) { if(i&1) b=b*a; a=a*a; i>>=1; } return b; } void pushup(int u){ tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum; } void build(int u,int l,int r){ if(l==r){ tr[u]={l,r,qpow(Q,a[l]-1),I}; } else{ tr[u]={l,r,I,I}; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } } void pushdown(int u){ tr[u<<1].sum=tr[u<<1].sum*tr[u].lazy; tr[u<<1|1].sum=tr[u<<1|1].sum*tr[u].lazy; tr[u<<1].lazy=tr[u<<1].lazy*tr[u].lazy; tr[u<<1|1].lazy=tr[u<<1|1].lazy*tr[u].lazy; tr[u].lazy=I; } void modify(int u,int l,int r,MA x){ if(tr[u].l>=l&&tr[u].r<=r){ tr[u].sum=tr[u].sum*x; tr[u].lazy=tr[u].lazy*x; return ; } if(tr[u].lazy!=I) pushdown(u); int mid=tr[u].l+tr[u].r>>1; if(l<=mid) modify(u<<1,l,r,x); if(r>mid) modify(u<<1|1,l,r,x); pushup(u); } MA query(int u,int l,int r){ if(tr[u].l>=l&&tr[u].r<=r){ return tr[u].sum; } if(tr[u].lazy!=I) pushdown(u); int mid=tr[u].l+tr[u].r>>1; MA res; if(l<=mid) res=res+query(u<<1,l,r); if(r>mid) res=res+query(u<<1|1,l,r); return res; } int main(){ ios::sync_with_stdio(false); cin>>n>>m; int i; init(); for(i=1;i<=n;i++) cin>>a[i]; build(1,1,n); while(m--){ int opt; cin>>opt; if(opt==1){ int l,r,x; cin>>l>>r>>x; modify(1,l,r,qpow(Q,x)); } else{ int l,r; cin>>l>>r; cout<<(P*query(1,l,r)).a[0][0]<<endl; } } return 0; }
没有人不辛苦,只有人不喊疼