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]);
    }
}

 

posted @ 2018-07-18 16:57  SiriusRen  阅读(358)  评论(0编辑  收藏  举报