C. 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) = 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 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 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.

Solution

题目大意:维护一个序列,支持两种操作:

1.区间[l,r]的权值+x

2.询问区间[l,r]的函数和,即$\sum _{x=l}^{r}fib(x)$这里的函数即斐波那契函数

一般求斐波那契函数的方法可以考虑矩阵乘法,这里也是这样的。

我们不用线段树维护权值,我们用线段树维护矩阵$fib^{a[l]-1}$。

矩阵的合并是可以相加的。

然后就可以了。

这道题很卡常数,我平常的习惯,矩阵是从1~n,而我这里要是从1开始就TLE了..所以应该从0~n-1

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define LL long long
inline int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define P 1000000007
#define MAXN 100010
int N,M,a[MAXN];
struct MatrixNode{LL a[][]; MatrixNode() {memset(a,,sizeof(a));}}fib;
MatrixNode operator + (MatrixNode x,MatrixNode y)
{
MatrixNode re;
for (int i=; i<=; i++)
for (int j=; j<=; j++)
re.a[i][j]=(x.a[i][j]+y.a[i][j])%P;
return re;
}
MatrixNode operator * (MatrixNode x,MatrixNode y)
{
MatrixNode re;
for (int k=; k<=; k++)
for (int i=; i<=; i++)
if (x.a[i][k])
for (int j=; j<=; j++)
if (y.a[k][j])
(re.a[i][j]+=(x.a[i][k]*y.a[k][j])%P)%=P;
return re;
}
MatrixNode operator ^ (MatrixNode x,int y)
{
MatrixNode re;
for (int i=; i<=; i++) re.a[i][i]=;
for (int i=y; i; i>>=,x=x*x) if (i&) re=re*x;
return re;
}
namespace SegmentTree
{
struct SegmentTreeNode{int l,r; MatrixNode tag,sum;}tree[MAXN<<];
#define ls now<<1
#define rs now<<1|1
inline void Update(int now) {tree[now].sum=tree[ls].sum+tree[rs].sum;}
inline void PushDown(int now)
{
if (tree[now].l==tree[now].r) return;
MatrixNode D=tree[now].tag;
tree[ls].sum=tree[ls].sum*D; tree[ls].tag=tree[ls].tag*D;
tree[rs].sum=tree[rs].sum*D; tree[rs].tag=tree[rs].tag*D;
memset(tree[now].tag.a,,sizeof(tree[now].tag.a));
for (int i=; i<=; i++) tree[now].tag.a[i][i]=;
}
inline void BuildTree(int now,int l,int r)
{
tree[now].l=l; tree[now].r=r;
for (int i=; i<=; i++) tree[now].tag.a[i][i]=;
if (l==r) {tree[now].sum=fib^(a[l]-); return;}
int mid=(l+r)>>;
BuildTree(ls,l,mid); BuildTree(rs,mid+,r);
Update(now);
}
inline void Modify(int now,int L,int R,MatrixNode D)
{
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (L<=l && R>=r) {tree[now].tag=tree[now].tag*D; tree[now].sum=tree[now].sum*D; return;}
int mid=(l+r)>>;
if (L<=mid) Modify(ls,L,R,D);
if (R>mid) Modify(rs,L,R,D);
Update(now);
}
inline MatrixNode Query(int now,int L,int R)
{
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (L<=l && R>=r) return tree[now].sum;
int mid=(l+r)>>; MatrixNode re;
if (L<=mid) re=re+Query(ls,L,R);
if (R>mid) re=re+Query(rs,L,R);
return re;
}
}
int main()
{
N=read(),M=read();
for (int i=; i<=N; i++) a[i]=read();
fib.a[][]=; fib.a[][]=; fib.a[][]=; fib.a[][]=;
SegmentTree::BuildTree(,,N);
while (M--)
{
int opt=read(),x,y,z;
switch (opt)
{
case : x=read(),y=read(),z=read(); SegmentTree::Modify(,x,y,fib^z); break;
case : x=read(),y=read(); printf("%I64d\n",SegmentTree::Query(,x,y).a[][]%P); break;
}
}
return ;
}

【Codeforces718C】Sasha and Array 线段树 + 矩阵乘法的更多相关文章

  1. CF718C Sasha and Array 线段树 + 矩阵乘法

    有两个操作: 将 $[l,r]$所有数 + $x$ 求 $\sum_{i=l}^{r}fib(i)$ $n=m=10^5$   直接求不好求,改成矩阵乘法的形式:  $a_{i}=M^x\times ...

  2. CF718C Sasha and Array 线段树+矩阵加速

    正解:线段树 解题报告: 传送门! 首先这种斐波拉契,又到了1e9的范围,又是求和什么的,自然而然要想到矩阵加速昂 然后这里主要是考虑修改操作,ai+=x如果放到矩阵加速中是什么意思呢QAQ? 那不就 ...

  3. CF718C Sasha and Array [线段树+矩阵]

    我们考虑线性代数上面的矩阵知识 啊呸,是基础数学 斐波那契的矩阵就不讲了 定义矩阵 \(f_x\) 是第 \(x\) 项的斐波那契矩阵 因为 \(f_i * f_j = f_{i+j}\) 然后又因为 ...

  4. CF719E. Sasha and Array [线段树维护矩阵]

    CF719E. Sasha and Array 题意: 对长度为 n 的数列进行 m 次操作, 操作为: a[l..r] 每一项都加一个常数 C, 其中 0 ≤ C ≤ 10^9 求 F[a[l]]+ ...

  5. Codeforces Round #373 (Div. 2) E. Sasha and Array 线段树维护矩阵

    E. Sasha and Array 题目连接: http://codeforces.com/contest/719/problem/E Description Sasha has an array ...

  6. codeforces 719E E. Sasha and Array(线段树)

    题目链接: E. Sasha and Array time limit per test 5 seconds memory limit per test 256 megabytes input sta ...

  7. hdu 5068(线段树+矩阵乘法)

    矩阵乘法来进行所有路径的运算, 线段树来查询修改. 关键还是矩阵乘法的结合律. Harry And Math Teacher Time Limit: 5000/3000 MS (Java/Others ...

  8. 【对不同形式矩阵的总结】WC 2009 最短路径问题(线段树+矩阵乘法)

    题意 ​ 题目链接:https://www.luogu.org/problem/P4150 ​ 一个 \(6\times n\) 的网格图,每个格点有一个初始权值.有两种操作: 修改一个格子的权值 求 ...

  9. MAZE(2019年牛客多校第二场E题+线段树+矩阵乘法)

    题目链接 传送门 题意 在一张\(n\times m\)的矩阵里面,你每次可以往左右和下三个方向移动(不能回到上一次所在的格子),\(1\)表示这个位置是墙,\(0\)为空地. 现在有\(q\)次操作 ...

随机推荐

  1. Android View的几个位置坐标关系

    1. View的边界,left, top, right, bottom(即左上右下),这些值都是相对View的父容器说的: 2. View的x, translationX, y, translatio ...

  2. iOS开发之功能模块--长方形UIImage截取中间最大正方形区域

    这里直接用CoreGraphics的一些处理图片的方法,本身不难,但是有些时候用的不多,就会遗忘掉使用方法的细节.下面就直接展示关键源码,以便下次重复需求,就可以立马找回. 该方法中在UIImage的 ...

  3. Shell: test

    基本格式:test expression expression为test命令构造的表达式.这里expression是test命令可以理解的任何有效表达式,该简化格式将是读者可能会踫见的最常用格式返回值 ...

  4. mysql中类似indexOf的方法LOCATE()

     LOCATE(substr,str), LOCATE(substr,str,pos) 第一个语法返回substr在字符串str 的第一个出现的位置. 第二个语法返回子符串 substr 在字符串st ...

  5. js快速判断IE浏览器(兼容IE10与IE11)

    在很多时候,我们一般采用navigator.userAgent和正则表达来判断IE浏览器版本,下面介绍用IE浏览器中不同特性来判断IE浏览器   1 判断IE浏览器与非IE 浏览器 IE浏览器与非IE ...

  6. 智力火柴游戏Android源码项目

    该游戏源码是一个智力火柴游戏源码,游戏分为难.中.易三种模式,通过对火柴的移动来实现等式分成立,具有极好的市场价值和参考意义. 源码下载: http://code.662p.com/view/9741 ...

  7. 【每日一linux命令6】命令中的命令

    许多命令在执行后,会进入该命令的操作模式,如 fdisk.pine.top 等,进入后我们必须要使用该 命令中的命令,才能正确执行:而一般要退出该命令,可以输入 exit.q.quit 或是按[Ctr ...

  8. 嵌入式Linux驱动学习之路(十八)LCD驱动

    驱动代码: /************************************************************************* > File Name: lcd ...

  9. python高级之多线程

    python高级之多线程 本节内容 线程与进程定义及区别 python全局解释器锁 线程的定义及使用 互斥锁 线程死锁和递归锁 条件变量同步(Condition) 同步条件(Event) 信号量 队列 ...

  10. 关于webpack编译scss文件

    css加载器文件通常和extract-text-webpack-plugin一块使用,我们可以在源文件src目录下写scss文件,然后通过webpack编译成css文件到输出目录public,这个目录 ...