Codeforces 718C 线段树+矩乘
题意:
维护一个序列,支持两种操作:
1.区间[l,r]的权值+x
2.询问区间[l,r]的函数和,即∑fib(x)这里的函数即斐波那契函数
数据范围:1≤n,q≤105
思路:
一般求斐波那契函数的方法可以考虑矩阵乘法,这里也是这样的。
我们不用线段树维护权值,我们用线段树维护线段树维护区间矩阵和。
有一个矩阵乘法的性质:A*B+A*C=A*(B+C)
在求斐波那契数列中,是A*F,A是变换矩阵,F是列矩阵
那么我们用线段树的lazy标记维护A矩阵,然后用sum维护F矩阵
之后在线段树上,就变成了区间更新乘以x。
//By SiriusRen #include <bits/stdc++.h> using namespace std; const int mod=1000000007,N=100050; int n,m,op,xx,yy,zz; struct Matrix{ int a[2][2]; void init(){memset(a,0,sizeof(a));} void dia(){a[0][0]=a[1][1]=1,a[0][1]=a[1][0]=0;} }sum[N<<3],lazy[N<<3],base; Matrix operator*(Matrix a,Matrix b){ Matrix c;c.init(); for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) c.a[i][j]=(1ll*a.a[i][k]*b.a[k][j]+c.a[i][j])%mod; return c; } Matrix operator+(Matrix a,Matrix b){ Matrix c;c.init(); for(int i=0;i<2;i++) for(int j=0;j<2;j++) c.a[i][j]=(a.a[i][j]+b.a[i][j])%mod; return c; } Matrix operator^(Matrix a,int b){ Matrix c;c.dia(); while(b){ if(b&1)c=c*a; a=a*a,b>>=1; }return c; } void push_up(int pos){sum[pos]=sum[pos<<1]+sum[pos<<1|1];} void build(int l,int r,int pos){ if(l==r){scanf("%d",&xx);sum[pos]=base^(xx-1);return;} int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; build(l,mid,lson),build(mid+1,r,rson); lazy[pos].dia(),push_up(pos); } void push_down(int pos,int lson,int rson){ lazy[lson]=lazy[lson]*lazy[pos],sum[lson]=sum[lson]*lazy[pos]; lazy[rson]=lazy[rson]*lazy[pos],sum[rson]=sum[rson]*lazy[pos]; lazy[pos].dia(); } Matrix query(int l,int r,int pos,int L,int R){ if(l>=L&&r<=R)return sum[pos]; int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; push_down(pos,lson,rson); if(mid<L)return query(mid+1,r,rson,L,R); else if(mid>=R)return query(l,mid,lson,L,R); else return query(l,mid,lson,L,R)+query(mid+1,r,rson,L,R); } void insert(int l,int r,int pos,int L,int R,Matrix wei){ if(l>=L&&r<=R){sum[pos]=sum[pos]*wei;lazy[pos]=lazy[pos]*wei;return;} int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; push_down(pos,lson,rson); if(mid<L)insert(mid+1,r,rson,L,R,wei); else if(mid>=R)insert(l,mid,lson,L,R,wei); else insert(l,mid,lson,L,R,wei),insert(mid+1,r,rson,L,R,wei); push_up(pos); } int main(){ base.a[0][0]=base.a[0][1]=base.a[1][0]=1; scanf("%d%d",&n,&m),build(1,n,1); while(m--){ scanf("%d%d%d",&op,&xx,&yy); if(op==1)scanf("%d",&zz),insert(1,n,1,xx,yy,base^zz); else printf("%d\n",query(1,n,1,xx,yy).a[0][0]); } }