关闭

CodeForces-719E Sasha and Array(线段树+矩阵快速幂)

标签: 线段树矩阵快速幂
475人阅读 评论(0) 收藏 举报
分类:
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 modulo109 + 7.

In this problem we define Fibonacci numbers as follows: f(1) = 1f(2) = 1f(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 0001 ≤ 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 tpiliri and may be xi (1 ≤ tpi ≤ 21 ≤ 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 11211.

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 13431.

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.

传送门:http://codeforces.com/problemset/problem/719/E
写过的最有意思的线段树,没有之一!
题意:给出有n个元素的数列ai(1<=i<=n)以及m次操作,操作分为两种:①将区间[l,r]的数加x;②询问∑f(ai)(l<=i<=r),其中f(x)是斐波那契数列的第x个数
题解:斐波那契数列可以由2*2矩阵A={1 1,1 0}相乘得到,因此可以想到用线段树存储矩阵,每次更新加x就可以用乘以A^x代替
#include<cstdio>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
const LL mod = 1e9 + 7;
const int maxn = 1e5 +5 ;
struct Mat{
    LL x[2][2];
    void init(){
        x[0][0]=x[1][1]=1;
        x[1][0]=x[0][1]=0;
    }
    Mat operator*(const Mat& m2)const{
        Mat m;
        m.x[0][0]=m.x[0][1]=m.x[1][0]=m.x[1][1]=0;
        for(int k=0;k<2;k++)
            for(int i=0;i<2;i++)
                for(int j=0;j<2;j++)
                    m.x[i][j]=(m.x[i][j]+x[i][k]*m2.x[k][j])%mod;
        return m;
    }
    Mat operator+(const Mat& m2)const{
        Mat m;
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                m.x[i][j]=(x[i][j]+m2.x[i][j])%mod;
        return m;
    }
};
Mat sum[maxn<<2],add[maxn<<2];
Mat pow(LL n){
    Mat m,ret;
    m.x[0][0]=1;m.x[0][1]=1;
    m.x[1][0]=1;m.x[1][1]=0;
    ret.init();
    while(n){
        if(n&1) ret=ret*m;
        m=m*m;
        n>>=1;
    }
    return ret;
}
LL solve(LL n){
    Mat ret=pow(n);
    return ret.x[0][0];
}
void PushUP(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt){
    sum[rt].init();
    add[rt].init();
    if(l==r){
        LL x;
        scanf("%I64d",&x);
        sum[rt]=pow(x-1);
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUP(rt);
}

void PushDown(int rt){
    sum[rt<<1]=sum[rt<<1]*add[rt];
    sum[rt<<1|1]=sum[rt<<1|1]*add[rt];
    add[rt<<1]=add[rt<<1]*add[rt];
    add[rt<<1|1]=add[rt<<1|1]*add[rt];
    add[rt].init();
}

void update(int L,int R,Mat c,int l,int r,int rt){
    if(L<=l&&R>=r){
        sum[rt]=sum[rt]*c;
        add[rt]=add[rt]*c;
        return;
    }
    PushDown(rt);
    int m=(l+r)>>1;
    if(L<=m) update(L,R,c,lson);
    if(R>m) update(L,R,c,rson);
    PushUP(rt);
}

LL query(int L,int R,int l,int r,int rt){
    if(L<=l&&R>=r){
        return sum[rt].x[0][0];
    }
    PushDown(rt);
    int m=(l+r)>>1;
    LL ret=0;
    if(L<=m) ret=(ret+query(L,R,lson))%mod;
    if(R>m) ret=(ret+query(L,R,rson))%mod;
    PushUP(rt);
    return ret;
}
void print(int l,int r,int rt){
    if(l==r){
        for(int i=0;i<2;i++){
            for(int j=0;j<2;j++)
                printf("%I64d ",sum[rt].x[i][j]);
            printf("\n");
        }
        printf("\n");
        return;
    }
    int m=(l+r)>>1;
    print(lson);
    print(rson);
}
int main(){
    int n,m;
   // freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m)){
        build(1,n,1);
        int op,a,b;
        LL x;
        while(m--){
            scanf("%d%d%d",&op,&a,&b);
            if(op==1) {
                scanf("%I64d",&x);
                Mat m=pow(x);
                update(a,b,m,1,n,1);
               // print(1,n,1);
            }
            else printf("%I64d\n",query(a,b,1,n,1));
        }

    }

    return 0;
}


0
0
查看评论

HAUToj 1284: SP教数学 (线段树+矩阵快速幂

1284: SP教数学DescriptionInputOutput对于每组数据的2操作,输出一行对1e9 + 7取模的答案Sample Input7 4 2 2 1 1 3 3 2 2 1 5 2 6 7 1 3 4 3 2 6 6Sample Output6 3 2题解:线段树+矩阵快速幂 出题人...
  • wang2332
  • wang2332
  • 2017-08-05 01:57
  • 454

线段树+矩阵快速幂 codeforces718C Sasha and Array

传送门:点击打开链接 题意:操作1,区间[l,r]的数字+x 操作2,求sigma f(i),l 答案取模1e9+7 首先斐波那契数列用矩阵快速幂求,谁都会的。 这里有一个矩阵乘法的性质,A*B+A*C=A*(B+C) 有了这个性质,这题就非常傻逼了。 在求斐波那契数列中,是A*F,A...
  • qwb492859377
  • qwb492859377
  • 2016-09-24 09:55
  • 769

【CodeForces 719E】【线段树+矩阵快速幂】 Sasha and Array

传送门:E. Sasha and Array 描述: E. Sasha and Array time limit per test 5 seconds memory limit per test 256 megabytes input standard...
  • guhaiteng
  • guhaiteng
  • 2016-10-04 22:16
  • 180

[Codeforces 719 E. Sasha and Array] 矩阵快速幂+线段树

[Codeforces 719 E. Sasha and Array] 矩阵快速幂+线段树题目链接:[Codeforces 719 E. Sasha and Array] 题意描述:给定NN个数a1,a2,…,ana_1,a_2,\ldots,a_n,有MM次操作。操作11:将连续区间aL,aL...
  • ACMore_Xiong
  • ACMore_Xiong
  • 2016-09-28 20:05
  • 593

CodeForces - 719E Sasha and Array 线段树 + 矩阵快速幂

传送门:CF 719 E题解 区间更新 注意这里节点是矩阵, 所以初始化要是E 矩阵结合律 + Fibo la表示lazy不过这里是矩阵, 所以初始是E, sum是区间的ans矩阵, lazy纯粹的标记 AC code:/* adrui's submission La...
  • ADjky
  • ADjky
  • 2016-12-09 23:05
  • 248

【Codeforces 718C&719E】Sasha and Array【线段树成段更新+矩阵快速幂】

题意:给你一个数列,有两种操作1 l r x 给[l,r]区间上的数加上x, 2 l r 询问[l,r]区间fibonacci数列的和(f[l]+f[l+1]+……f[r]) 题解:这样的区间加和区间询问很容易想到线段树成段更新,关键是怎么存储信息,我们都知道fibonacci数列可以用矩阵快速幂递...
  • sjtsjt709
  • sjtsjt709
  • 2016-10-04 16:57
  • 365

cf/Codeforces Round #373 div1-C/div2-E Sasha and Array 线段树 + 维护矩阵快速幂

http://codeforces.com/contest/718/problem/C 题意:  n个数,维护两个操作,操作1,【l,r】区间每个位置+x,操作2,【l,r】区间内,以每个位置上的数字为下标的斐波那契数列的和,%1e9+7 把每个节点看成一个斐波那契矩阵,也就是 【...
  • viphong
  • viphong
  • 2016-09-24 01:20
  • 360

E. Sasha and Array——矩阵+线段树

E.Sasha and Array 很神奇的一道题 题意大概就是支持区间加,然后求区间和。。。 区间和的求法是 sigema(i,l,r) f[i]  f[i]表示斐波那契序列第i项 例如一个区间的数字是1 2 3 4 5 6  那么其和为1+1+2+3+5+8=20 看到数...
  • Fop_zz
  • Fop_zz
  • 2017-06-15 10:15
  • 145

Codeforces 718C Sasha and Array(线段树维护矩阵)

线段树上区间加和,求和时候值变成斐波那契数列下标,对斐波那契数列求和线段树上区间加和,求和时候值变成斐波那契数列下标,对斐波那契数列求和 首先想到循环节,但是应该很大,所以GG首先想到循环节,但是应该很大,所以GG 然后就是想到对于斐波那契数列啊,有矩阵递推然后就是想到对于斐波那契数列啊,有矩阵...
  • Miracle_ma
  • Miracle_ma
  • 2016-09-29 14:48
  • 539

CodeForces 719E Sasha and Array 【线段树】【快速矩阵幂】

题目:点击打开链接 题意:给出有n个元素的数列ai(1 分析:容易想到用快速矩阵幂求斐波那契数列,同时用线段树储存和矩阵以及lazy矩阵,如果lazy标记为指数的话每次更新都要用一遍快速矩阵幂,就会超时。因为矩阵乘法满足分配律,且区间[l,r]加上x可以表示为乘上x次q矩阵,所以线段树维护矩阵之...
  • pan1197349032
  • pan1197349032
  • 2016-11-17 20:22
  • 110
    个人资料
    • 访问:57429次
    • 积分:2811
    • 等级:
    • 排名:第15057名
    • 原创:230篇
    • 转载:4篇
    • 译文:0篇
    • 评论:7条
    最新评论