zoukankan      html  css  js  c++  java
  • Codeforces Round #373 (Div. 2) E. Sasha and Array

     
    E. Sasha and Array
    time limit per test:5 seconds
    memory limit per test:256 megabytes
    input: standard input
    output: standard output

    Sasha has an array of integers a1, a2, ..., an. You have to perform m queries. There might be queries of two types:

    1. 1 l r x — increase all integers on the segment from l to r by values x;
    2. 2 l r — find , where f(x) is the x-th Fibonacci number. As this number may be large, you only have to find it modulo 109 + 7.

    In this problem we define Fibonacci numbers as follows: f(1) = 1, f(2) = 1, f(x) = f(x - 1) + f(x - 2) for all x > 2.

    Sasha is a very talented boy and he managed to perform all queries in five seconds. Will you be able to write the program that performs as well as Sasha?

    Input

    The first line of the input contains two integers n and m (1 ≤ n ≤ 100 000, 1 ≤ m ≤ 100 000) — the number of elements in the array and the number of queries respectively.

    The next line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 109).

    Then follow m lines with queries descriptions. Each of them contains integers tpi, li, ri and may be xi (1 ≤ tpi ≤ 2, 1 ≤ li ≤ ri ≤ n, 1 ≤ xi ≤ 109). Here tpi = 1 corresponds to the queries of the first type and tpi corresponds to the queries of the second type.

    It's guaranteed that the input will contains at least one query of the second type.

    Output

    For each query of the second type print the answer modulo 109 + 7.

    Examples
    Input
    5 4
    1 1 2 1 1
    2 1 5
    1 2 4 2
    2 2 4
    2 1 5
    Output
    5
    7
    9
    Note

    Initially, array a is equal to 1, 1, 2, 1, 1.

    The answer for the first query of the second type is f(1) + f(1) + f(2) + f(1) + f(1) = 1 + 1 + 1 + 1 + 1 = 5.

    After the query 1 2 4 2 array a is equal to 1, 3, 4, 3, 1.

    The answer for the second query of the second type is f(3) + f(4) + f(3) = 2 + 3 + 2 = 7.

    The answer for the third query of the second type is f(1) + f(3) + f(4) + f(3) + f(1) = 1 + 2 + 3 + 2 + 1 = 9.

    题意:

    给定一个数组a[],有两种操作:1 l r x —— a[l]~a[r]每个元素加x

    2 l r—— 求 , 其中f 为fibonacci数列

    题解:

    线段树成段更新,lazy标记。

    线段树基础算法参考:http://blog.csdn.net/zhou_yujia/article/details/51386549

    重点在于求fibonacci数列。

    , f[]表示fibonacci数列可以利用矩阵快速幂求出。

    , 则f[i]=(F^n).mat[0][1];

    当然

    于是可以构造线段树,线段树的叶子节点不是某个实数,而是一个矩阵 (F^ai)

    操作 1 l r x ,成段更新时

    a数组[l,r] 每个元素加x,即对应线段树[l,r]每个叶子节点矩阵 乘 (F^x)

    可以设定一个数组add[]表示懒惰,设定另一个矩阵数组lazy[]用于pushdown实际操作。

    剩下的就是典型的线段树成段更新lazy标记的内容了。

    #include <algorithm>
    #include <cstring>
    #include <string.h>
    #include <iostream>
    #include <list>
    #include <map>
    #include <set>
    #include <stack>
    #include <string>
    #include <utility>
    #include <vector>
    #include <cstdio>
    #include <cmath>
    
    #define LL long long
    #define N 100005
    #define INF 0x3ffffff
    
    using namespace std;
    
    const int mod = 1e9+7;
    
    struct Matrix{
        int m[2][2];
        void init(){
            memset(m,0,sizeof(m));
        }
        Matrix operator+(const Matrix&a)const
        {
            Matrix ret;
            ret.m[0][0]=(m[0][0]+a.m[0][0])%mod;
            ret.m[0][1]=(m[0][1]+a.m[0][1])%mod;
            ret.m[1][0]=(m[1][0]+a.m[1][0])%mod;
            ret.m[1][1]=(m[1][1]+a.m[1][1])%mod;
            return ret;
        }
        Matrix operator*(const Matrix&a)
        {
            Matrix ret;
            ret.m[0][0]=(1ll*m[0][0]*a.m[0][0]+1ll*m[0][1]*a.m[1][0])%mod;
            ret.m[1][0]=ret.m[0][1]=(1ll*m[0][0]*a.m[0][1]+1ll*m[0][1]*a.m[1][1])%mod;
            ret.m[1][1]=(1ll*m[1][0]*a.m[0][1]+1ll*m[1][1]*a.m[1][1])%mod;
            return ret;
        }
    };
    
    int n,m;
    Matrix tree[N<<2];
    int add[N<<2];            //add[]表示懒惰标记
    Matrix lazy[N<<2];      //成段更新时实际使用的lazy矩阵
    Matrix I;                //单位矩阵
    Matrix F;              //Fibonacci矩阵
    
    void init()
    {
        F.init();
        I.init();
        F.m[0][0]=F.m[1][0]=F.m[0][1]=1;
        I.m[0][0]=I.m[1][1]=1;
    }
    
    Matrix pow(int x)   //矩阵快速幂
    {
        Matrix ret=I;
        Matrix tmp=F;
        while(x>0)
            {
                if(x&1) ret=ret*tmp;
                tmp=tmp*tmp;
                x>>=1;
            }
        return ret;
    }
    void build_tree(int rt,int l,int r)
    {
        lazy[rt]=I;
        if(l==r){
            int a;
            scanf("%d",&a);
            if(a==1) tree[rt]=I;
            else tree[rt]=pow(a-1);
            return;
        }
        int mid=l+r>>1;
        build_tree(rt<<1,l,mid);
        build_tree(rt<<1|1,mid+1,r);
        tree[rt]=tree[rt<<1]+tree[rt<<1|1];
    }
    
    void pushDown(int rt)   
    {
        if(add[rt])
        {
            add[rt<<1]+=add[rt];
            tree[rt<<1]=tree[rt<<1]*lazy[rt];
            lazy[rt<<1]=lazy[rt<<1]*lazy[rt];
            add[rt<<1|1]+=add[rt];
            tree[rt<<1|1]=tree[rt<<1|1]*lazy[rt];
            lazy[rt<<1|1]=lazy[rt<<1|1]*lazy[rt];
            add[rt]=0;
            lazy[rt]=I;
        }
    }
    void update(int rt,int l,int r,int L ,int R,int v)  //表示对区间[L,R]内的每个数均加v,rt是根节点
    //  实际对应线段树区间[L,R]每个节点的矩阵乘 pow(v)
    { if(L<=l&&r<=R) { Matrix P=pow(v); //数组元素+v, 对应线段树相应节点矩阵 * pow(v) tree[rt]=tree[rt]*P; lazy[rt]=lazy[rt]*P; add[rt]+=v; return; } pushDown(rt); int mid=l+r>>1; if(L<=mid)update(rt<<1,l,mid,L,R,v); if(mid<R)update(rt<<1|1,mid+1,r,L,R,v); tree[rt]=tree[rt<<1]+tree[rt<<1|1]; } Matrix query(int rt,int l,int r,int L,int R) { if(L<=l&&r<=R) { return tree[rt]; } int mid=l+r>>1; pushDown(rt); Matrix ret; ret.init(); if(L<=mid) ret=ret+query(rt<<1,l,mid,L,R); if(mid<R) ret=ret+query(rt<<1|1,mid+1,r,L,R); return ret; } int main() { scanf("%d%d",&n,&m); init(); build_tree(1,1,n); while(m--) { int op,l,r,v; scanf("%d%d%d",&op,&l,&r); if(op==1){ scanf("%d",&v); update(1,1,n,l,r,v); } else{ Matrix ans=query(1,1,n,l,r); printf("%d ",ans.m[0][0]); } } return 0; }
  • 相关阅读:
    PPK提供的浏览器类型及版本检测方法
    从KPI到OKR,高阶产品人如何推动业务高速增长
    线上流量越发昂贵,如何通过裂变营销实现业务增长?
    快速了解云原生架构
    阿里巴巴超大规模中台型团队研发提效实践
    如何通过数据智能玩转私域流量新生态
    Serverless Kubernetes:理想,现实与未来
    这只猫在云端定居了?边缘计算在天猫精灵云应用上的落地实践
    阿里毕玄:提升代码能力的4段经历
    你女朋友在买买买时,程序员小哥在干嘛?
  • 原文地址:https://www.cnblogs.com/smartweed/p/5904385.html
Copyright © 2011-2022 走看看