题解
(不会矩阵加速的先去学矩阵加速)
反正我想不到线段树维护矩阵。我太菜了。
我们在线段树上维护一个区间的斐波那契的列矩阵的和。
然后询问时提取每个符合题意列矩阵的答案项(不是列矩阵存了两项吗,一个是当前项,一个是用来递推的)
因为矩阵乘有结合律所以区间加这个操作就直接区间乘变换矩阵的x次方就行。
然后记得开long long
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const long long mod=1e9+7; 8 const long long N=100100; 9 long long n,m; 10 struct jz{ 11 long long a[3][3]; 12 }e,h,be,f[N],ma; 13 struct tree{ 14 long long l,r; 15 jz sum,lazy; 16 }tr[N*5]; 17 jz jzc(jz a,jz b,jz c){ 18 for(long long i=1;i<=2;i++) 19 for(long long j=1;j<=2;j++) 20 for(long long k=1;k<=2;k++){ 21 c.a[i][j]+=a.a[i][k]*b.a[k][j]; 22 c.a[i][j]%=mod; 23 } 24 return c; 25 } 26 jz ksm(long long b,jz x){ 27 jz ans; 28 ans=ma; 29 while(b){ 30 if(b&1){ 31 ans=jzc(ans,x,h); 32 } 33 b>>=1; 34 x=jzc(x,x,h); 35 } 36 return ans; 37 } 38 void update(long long now){ 39 tr[now].sum.a[1][1]=(tr[now*2].sum.a[1][1]+tr[now*2+1].sum.a[1][1])%mod; 40 tr[now].sum.a[1][2]=(tr[now*2].sum.a[1][2]+tr[now*2+1].sum.a[1][2])%mod; 41 } 42 void build(long long l,long long r,long long now){ 43 tr[now].l=l;tr[now].r=r;tr[now].lazy=ma; 44 if(l==r){ 45 tr[now].sum=f[l]; 46 return; 47 } 48 long long mid=(l+r)>>1; 49 build(l,mid,now*2); 50 build(mid+1,r,now*2+1); 51 update(now); 52 } 53 bool pd(jz a,jz b){ 54 for(long long i=1;i<=2;i++) 55 for(long long j=1;j<=2;j++) 56 if(a.a[i][j]!=b.a[i][j])return false; 57 return true; 58 } 59 void pushdown(long long now){ 60 if(pd(tr[now].lazy,ma))return; 61 tr[now*2].sum=jzc(tr[now*2].sum,tr[now].lazy,h); 62 tr[now*2+1].sum=jzc(tr[now*2+1].sum,tr[now].lazy,h); 63 tr[now*2].lazy=jzc(tr[now*2].lazy,tr[now].lazy,h); 64 tr[now*2+1].lazy=jzc(tr[now*2+1].lazy,tr[now].lazy,h); 65 tr[now].lazy=ma; 66 } 67 void add(long long l,long long r,long long now,jz x){ 68 pushdown(now); 69 if(tr[now].l==l&&tr[now].r==r){ 70 tr[now].sum=jzc(tr[now].sum,x,h); 71 tr[now].lazy=x; 72 return; 73 } 74 long long mid=(tr[now].l+tr[now].r)>>1; 75 if(l>mid)add(l,r,now*2+1,x); 76 else if(r<=mid)add(l,r,now*2,x); 77 else{ 78 add(l,mid,now*2,x); 79 add(mid+1,r,now*2+1,x); 80 } 81 update(now); 82 } 83 long long query(long long l,long long r,long long now){ 84 pushdown(now); 85 if(tr[now].l==l&&tr[now].r==r){ 86 return tr[now].sum.a[1][2]; 87 } 88 long long mid=(tr[now].l+tr[now].r)>>1; 89 if(l>mid)return query(l,r,now*2+1); 90 else if(r<=mid)return query(l,r,now*2); 91 else return (query(l,mid,now*2)+query(mid+1,r,now*2+1))%mod; 92 } 93 int main(){ 94 scanf("%lld%lld",&n,&m); 95 e.a[1][1]=0;e.a[1][2]=e.a[2][1]=e.a[2][2]=1; 96 be.a[1][1]=0;be.a[1][2]=1; 97 for(long long i=1;i<=2;i++) 98 for(long long j=1;j<=2;j++) 99 if(i==j)ma.a[i][j]=1; 100 else ma.a[i][j]=0; 101 for(long long i=1;i<=n;i++){ 102 long long x; 103 scanf("%lld",&x); 104 if(x==1)f[i]=be; 105 else f[i]=jzc(be,ksm(x-1,e),h); 106 } 107 build(1,n,1); 108 for(long long i=1;i<=m;i++){ 109 long long k; 110 scanf("%lld",&k); 111 if(k==1){ 112 long long l,r,x; 113 scanf("%lld%lld%lld",&l,&r,&x); 114 add(l,r,1,ksm(x,e)); 115 } 116 else{ 117 long long l,r; 118 scanf("%lld%lld",&l,&r); 119 printf("%lld\n",query(l,r,1)); 120 } 121 } 122 return 0; 123 }
原文地址:https://www.cnblogs.com/Xu-daxia/p/9403450.html
时间: 2024-10-10 21:10:41