CF718C Sasha and Array(线段树维护矩阵)

题解

(不会矩阵加速的先去学矩阵加速)

反正我想不到线段树维护矩阵。我太菜了。

我们在线段树上维护一个区间的斐波那契的列矩阵的和。

然后询问时提取每个符合题意列矩阵的答案项(不是列矩阵存了两项吗,一个是当前项,一个是用来递推的)

因为矩阵乘有结合律所以区间加这个操作就直接区间乘变换矩阵的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 }
View Code

 

posted @ 2018-08-01 19:18  Xu-daxia  阅读(367)  评论(0编辑  收藏  举报