zoukankan      html  css  js  c++  java
  • 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
    ",query(1,n,1,xx,yy).a[0][0]);
        }
    }
  • 相关阅读:
    linux cpu load学习笔记
    P1064 金明的预算方案
    P1757 通天之分组背包
    P1352 没有上司的舞会
    P1651 塔
    P1250 种树
    P1938 [USACO09NOV]找工就业Job Hunt
    P4392 [BOI2007]Sound 静音问题
    P3884 [JLOI2009]二叉树问题
    P2880 [USACO07JAN]平衡的阵容Balanced Lineup
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/9330257.html
Copyright © 2011-2022 走看看