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; }
  • 相关阅读:
    工作中常用,实用工具推荐!
    “如何管理好你的时间”
    经典SQL语句大全(绝对的经典eweqweqwe)
    第三节 MongoDB下samus源码初探
    ASP.NET(C#)常用数据加密和解密方法汇总
    全自动时代:JavaScript自动压缩插件
    SQL Server 获取所有表和数据的批量操作
    千万级别数据表,单列索引和多列索引性能对比
    第二节 为什么用MongoDB及.NET开发入门
    vs2005手机开发环境的配置
  • 原文地址:https://www.cnblogs.com/smartweed/p/5904385.html
Copyright © 2011-2022 走看看