Sasha and Array (线段树 + 快速幂)

本文描述了一道编程题目,涉及到一个整数数组和一系列操作,包括增加数组段上的数值以及计算斐波那契数列的段和,所有计算都取模10^9+7。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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?

输入

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 tpiliri 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 tpicorresponds to the queries of the second type.

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

输出

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

样例

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

注意

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.

------------------------------------------------------------

题目大意:两个操作 1 l r x(从l到r上的值+x)2 l r(斐波那契求和)

 

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll mod=1e9+7;
ll a[maxn];

struct node
{
    ll a[2][2];
};
node add(node A,node B)//矩阵相加
{
    node C;
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            C.a[i][j]=A.a[i][j]+B.a[i][j];
            if(C.a[i][j]>=mod)C.a[i][j]-=mod;
        }
    }
    return C;
}
node mul(node A,node B)//矩阵相乘
{
    node C = {0};
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            for(int k=0; k<2; k++)
            {
                C.a[i][j] = (C.a[i][j] + (A.a[i][k]*B.a[k][j]))%mod;
            }
        }
    }
    return C;
}
node pow_mod(ll x)//矩阵快速幂
{
    node s;
    node y;
    s.a[0][0]=s.a[1][1]=1;//单位矩阵
    s.a[0][1]=s.a[1][0]=0;
    y.a[0][0]=y.a[0][1]=y.a[1][0]=1;//转换矩阵
    y.a[1][1]=0;
    while(x)
    {
        if(x&1)s=mul(s,y);
        y=mul(y,y);
        x>>=1;
    }
    return s;
}


struct Tree
{
    int l,r,mark;
    node sum,fs;
} tr[4*maxn];
inline void pushup(int o)//更新节点
{
    tr[o].sum=add(tr[2*o].sum,tr[2*o+1].sum);//矩阵相加
}
inline void pushdown(int o)
{
    if(tr[o].mark)
    {
        tr[o].mark=0;
        tr[2*o].mark=1;
        tr[2*o+1].mark=1;
        tr[2*o].sum=mul(tr[2*o].sum,tr[o].fs);
        tr[2*o+1].sum=mul(tr[2*o+1].sum,tr[o].fs);
        tr[2*o].fs=mul(tr[2*o].fs,tr[o].fs);
        tr[2*o+1].fs=mul(tr[2*o+1].fs,tr[o].fs);
        tr[o].fs.a[0][0]=tr[o].fs.a[1][1]=1;
        tr[o].fs.a[1][0]=tr[o].fs.a[0][1]=0;
    }
}
void build(int o,int L,int R)
{
    tr[o].l=L;
    tr[o].r=R;
    tr[o].mark=0;
    tr[o].fs.a[0][0]=tr[o].fs.a[1][1]=1;//单位矩阵
    tr[o].fs.a[0][1]=tr[o].fs.a[1][0]=0;
    if(L>=R)
    {
        tr[o].sum=pow_mod(a[L]);//节点存矩阵的快速幂
        return ;
    }
    int mid=(L+R)/2;
    build(2*o,L,mid);
    build(2*o+1,mid+1,R);
    pushup(o);
}
ll query(int o,int L,int R)//各节点斐波那契数值加和
{
    if(L<=tr[o].l&&R>=tr[o].r)
    {
    return tr[o].sum.a[0][0];
    }
    int mid=(tr[o].l+tr[o].r)/2;
    pushdown(o);
    ll ans=0;
    if(L<=mid)ans+=query(2*o,L,R);
    if(R>mid)ans+=query(2*o+1,L,R);
    pushup(o);
    return ans%mod;
}
void update(int o,int L,int R,node num)//区间更新
{
    if(L<=tr[o].l&&R>=tr[o].r)
    {
        tr[o].fs=mul(tr[o].fs,num);
        tr[o].mark=1;
        tr[o].sum=mul(tr[o].sum,num);
        return ;
    }
    pushdown(o);
    int mid=(tr[o].l+tr[o].r)/2;
    if(L<=mid)update(2*o,L,R,num);
    if(R>mid)update(2*o+1,L,R,num);
    pushup(o);
}


int n,m;
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1; i<=n; i++)
    {
      scanf("%lld",&a[i]);
      a[i]--;//次数应为-1次
    }
    build(1,1,n);
    int op,u,v;
    ll temp;
    while(m--)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d %d %lld",&u,&v,&temp);
            node num=pow_mod(temp);//转换矩阵的t-1次方
            update(1,u,v,num);
        }
        else
        {
            scanf("%d %d",&u,&v);
            printf("%lld\n",query(1,u,v));
        }
    }
    return 0;
}

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值