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

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

    1 l r x — increase all integers on the segment from l to r by values x;
    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.

小编提示:
此题开始每使用线段数,WA好几次,也不知道错在哪。(感觉运行到最后也要超时)because:用完线段数的代码用时1560ms,也很长了。
线段数比较麻烦,感觉不画图不好懂,所以研究半天+借鉴了一波终于AC了

注意:此题使用的是懒人法线段数求和(正规线段数感觉会超时)

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int mod = 1000000007;
const int maxn = 1e5+10;
typedef long long ll;
struct two
{
    ll a[2][2];
    void em()**//矩阵清零**
    {
        memset(a,0,sizeof(a));
    }
    void one()**//矩阵初始化**
    {
        em();
        a[0][0]=a[1][1]=1;
    }
};

ll a[maxn];
int n,q;

two add(two a,two b)**//矩阵相加**
{
    two k;
    k.em();
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            k.a[i][j]=(a.a[i][j]+b.a[i][j])%mod;
        }
    }
    return k;
}

two mul(two a,two b)**//矩阵相乘**
{
    two k;
    k.em();
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            for(int t=0; t<2; t++)
            {
                k.a[i][j]=(k.a[i][j]+a.a[i][t]*b.a[t][j])%mod;
            }
        }
    }
    return k;
}

two mi(int x)**//矩阵快速幂**
{
    two a;
    a.a[0][0]=0,a.a[1][0]=1,a.a[0][1]=1,a.a[1][1]=1;
    two b;
    b.one();
    while(x)
    {
        if(x&1)**//二进制为一的or奇数**
        {
            b=mul(b,a);
        }
        a=mul(a,a);
        x=x/2;
    }
    return b;
}

typedef two tr;

struct node
{
    int ltree,rtree,flag;
    tr sum, lazy;
    void change(tr x)**//变换成矩阵运算**
    {
        sum=mul(sum,x);**//sum的更新**
        lazy=mul(lazy,x);**//lazy的更新**
        flag=1;**//flag标记置为1**
    }
};

node tree[maxn*4];

void pushdown(int x)
{
    if(tree[x].flag==1)
    {
        tree[2*x].change(tree[x].lazy);
        tree[2*x+1].change(tree[x].lazy);
        tree[x].flag = 0;**//flag标记置为0**
        tree[x].lazy.one();**//lazy初始化(must)**
    }
}

void pushup(int x)
{
    tree[x].sum=add(tree[x*2].sum,tree[x*2+1].sum);**//更新父节点**
}

void buildtree(int l, int r, int x)**//建树**
{
    tree[x].ltree=l, tree[x].rtree=r,tree[x].sum.em(),tree[x].lazy.one(),tree[x].flag=0;
    if(l==r)
    {
        tree[x].sum=mi(a[l]);**//初始化**
    }
    if(r>l)
    {
        int mid=(l+r)/2;
        buildtree(l,mid,x*2);
        buildtree(mid+1,r,x*2+1);
        pushup(x);
    }
}

void update(int l,int r,tr v,int x)
{
    int L=tree[x].ltree, R=tree[x].rtree;
    if (l<=L&&R<=r)
    {
        tree[x].change(v);
    }
    else
    {
        pushdown(x);**//向下传递lazy(must)**
        int mid=(L+R)>>1;
        if(l<=mid)
        {
            update(l,r,v,x*2);
        }
        if(r>mid)
        {
            update(l,r,v,x*2+1);
        }
        pushup(x);**//更新父节点(must)**
    }
}

tr query(int l,int r,int x)
{
    int L=tree[x].ltree, R=tree[x].rtree;
    if (l<=L&&R<=r)
    {
        return tree[x].sum;
    }
    else
    {
        pushdown(x);
        int mid=(L+R)/2;
        tr ans;
        ans.em();
        if(l<=mid)
        {
            ans=add(ans,query(l,r,2*x));
        }
        if(r> mid)
        {
            ans=add(ans,query(l,r,2*x+1));
        }
        pushup(x);
        return ans;
    }
}

int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1; i<=n; i++)
    {
        scanf("%lld",&a[i]);
    }
    buildtree(1,n,1);
    for(int i=1; i<=q; i++)
    {
        int po;
        scanf("%d",&po);
        if(po==1)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            update(a,b,mi(c),1);
        }
        else
        {
            int a,b;
            scanf("%d%d",&a,&b);
            printf("%lld\n",query(a,b,1).a[1][0]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZZ --瑞 hopeACMer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值