E. Sasha and Array——矩阵+线段树

来源:互联网 发布:java程序设计是什么 编辑:程序博客网 时间:2024/06/05 14:37

E.Sasha and Array

很神奇的一道题

题意大概就是支持区间加,然后求区间和。。。

区间和的求法是 sigma(i,l,r) f[i]  f[i]表示斐波那契序列第i项

例如一个区间的数字是1 2 3 4 5 6 

那么其和为1+1+2+3+5+8=20


看到数据范围。。那斐波那契肯定不能离线处理了,只能是用矩阵去算

那我们如果给一个数+x,相当于让他再乘x次,这样就可以用线段树求解了


那么问题出现了,我们的lazy标记要怎么打??

不打的话显然会退化到n^2,打的话这个和可不是一个整体


然而有一个东西叫做。。分配律

对于矩阵A,B,C

A*C+B*C=(A+B)*C

所以我们在线段树的每个节点上存下当前的一个矩阵总和的话,好像没什么毛病?答案那一项也就是我们原来想的那个答案

然后lazy标记我们可以打成是一个转移矩阵的^x次,这样我们就可以很轻松的Push下去了


(说实话这是第一次做题把矩阵的分配律用进去。。。。。


#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <queue>#include <string>#include <map>#include <cstring>#include <ctime>#include <vector>#define inf 1e9#define ll long long#define For(i,j,k) for(ll i=j;i<=k;i++)#define Dow(i,j,k) for(ll i=k;i>=j;i--)using namespace std;ll lson[500001],rson[500001],L[500001],R[500001],a[500001],rt,tot,n,k,ans;ll mo=1e9+7;struct mat{ll cube[3][3];mat(){cube[1][1]=cube[2][2]=0;cube[1][2]=cube[2][1]=0;}mat operator *(const mat &tx)const{mat tmp;For(k,1,2)For(i,1,2)if(cube[i][k])For(j,1,2)tmp.cube[i][j]+=(cube[i][k]*tx.cube[k][j])%mo,tmp.cube[i][j]%=mo;return tmp;}mat operator +(const mat &tx)const{mat tmp;For(i,1,2)For(j,1,2)tmp.cube[i][j]=cube[i][j]+tx.cube[i][j],tmp.cube[i][j]%=mo;return tmp;}}tag[500001],sum[500001],one,zero;inline mat ksm(mat x,ll y){if(y==0)return zero;mat sum=x;y--;for(;y;y/=2){if(y&1)sum=sum*x;x=x*x;}return sum;}inline void down(ll x){sum[lson[x]]=sum[lson[x]]*tag[x];sum[rson[x]]=sum[rson[x]]*tag[x];tag[lson[x]]=tag[lson[x]]*tag[x];tag[rson[x]]=tag[rson[x]]*tag[x];tag[x]=zero;}inline void build(ll &x,ll l,ll r){x=++tot;sum[x]=zero;tag[x]=zero;L[x]=l;R[x]=r;if(l==r){sum[x]=ksm(one,a[l]-1);return;}ll mid=(l+r)>>1;build(lson[x],l,mid);build(rson[x],mid+1,r);sum[x]=sum[lson[x]]+sum[rson[x]];}inline void update(ll x,ll l,ll r,mat v){if(l<=L[x]&&R[x]<=r){tag[x]=tag[x]*v;sum[x]=sum[x]*v;return;}down(x);if(l<=R[lson[x]])update(lson[x],l,r,v);if(r>=L[rson[x]])update(rson[x],l,r,v);sum[x]=sum[lson[x]]+sum[rson[x]];}inline ll query(ll x,ll l,ll r){if(l<=L[x]&&R[x]<=r)return sum[x].cube[1][1];down(x);ll ret=0;if(l<=R[lson[x]])ret+=query(lson[x],l,r),ret%=mo;if(r>=L[rson[x]])ret+=query(rson[x],l,r),ret%=mo;sum[x]=sum[lson[x]]+sum[rson[x]];return ret;}int main(){one.cube[1][1]=one.cube[1][2]=one.cube[2][1]=1;one.cube[2][2]=0;zero.cube[1][1]=zero.cube[2][2]=1;zero.cube[1][2]=zero.cube[2][1]=0;scanf("%lld%lld",&n,&k);For(i,1,n)scanf("%lld",&a[i]);build(rt,1,n);For(i,1,k){ll opt;scanf("%lld",&opt);if(opt==1){ll x,y,v;scanf("%lld%lld%lld",&x,&y,&v);mat tmp=ksm(one,v);update(1,x,y,tmp);}else{ll x,y;scanf("%lld%lld",&x,&y);ans=query(1,x,y);printf("%lld\n",ans);}}}


阅读全文
0 0