• 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; }
  • 相关阅读:
    日常排雷:redis报错 could not get a resource from the pool
    阿里云centos服务器tomcat启动后,浏览器请求无响应
    并发生产顺序单据号测试
    json 数据 格式,请求接口,部分字段无法注入
    baomidou 动态数据源@DS 使用问题
    SpringMVC框架深入(八)--SpringMVC原理
    Spring框架深入(七)--json数据交互
    框架理论深入(六)--拦截器
    Spring框架深入(五)--文件上传和异常处理
    int和Integer的区别
  • 原文地址:https://www.cnblogs.com/smartweed/p/5904385.html
Copyright © 2020-2023  润新知