有两个操作:

  • 将 $[l,r]$所有数 + $x$
  • 求 $\sum_{i=l}^{r}fib(i)$
$n=m=10^5$  
直接求不好求,改成矩阵乘法的形式: 
$a_{i}=M^x\times fib_{1}$
直接用线段树维护 $M^x$ 即可.
因为矩阵乘法是满足结合律的: $A*B+A*C=A*(B+C)$
#include <cstdio>
#include <algorithm>
#include <cstring>
#define lson (now << 1)
#define rson (now << 1 | 1)
#define ll long long
#define setIO(s) freopen(s".in", "r" , stdin)
using namespace std;
const int N = 200003;
const ll mod = 1000000007;
struct Matrix
{
int n, m;
ll a[4][4];
ll * operator[] (int x) { return a[x]; }
inline void re()
{
for(int i = 0; i < 3 ; ++i)
for(int j = 0; j < 3; ++j) a[i][j] = 0;
}
inline void I()
{
re();
for(int i = 0; i < 3 ; ++i) a[i][i] = 1ll;
}
Matrix friend operator * (Matrix a, Matrix b)
{
Matrix c;
c.re();
int i , j , k;
for(i = 0; i < a.n ; ++i)
{
for(j = 0; j < b.m ; ++j)
for(k = 0; k < a.m ; ++k)
{
c[i][j] = (c[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
}
}
c.n = a.n , c.m = b.m;
return c;
}
Matrix friend operator + (Matrix a, Matrix b)
{
Matrix c;
c.n = 2, c.m = 1;
for(int i = 0; i < c.n ; ++i)
{
for(int j = 0; j < c.m; ++j) c[i][j] = (a[i][j] + b[i][j]) % mod;
}
return c;
}
}A[N], M, fib1, v;
Matrix operator ^ (Matrix a, int k)
{
Matrix tmp;
tmp.n = tmp.m = 2;
for(tmp.I(); k ; a = a * a, k >>= 1) if(k & 1) tmp = tmp * a;
return tmp;
}
inline void init()
{
M.re(), fib1.re();
M.n = M.m = 2;
M[0][0] = 0, M[0][1] = 1, M[1][0] = 1, M[1][1] = 1;
fib1.n = 2, fib1.m = 1;
fib1[0][0] = 0, fib1[1][0] = 1;
}
int n , m ;
struct Node
{
Matrix sum, lazy;
int tag;
}t[N << 2];
inline void pushup(int l, int r, int now)
{
int mid = (l + r) >> 1;
t[now].sum = t[now << 1].sum;
if(r > mid) t[now].sum = t[now].sum + t[now << 1 | 1].sum;
}
inline void mark(int now, Matrix f)
{
t[now].sum = f * t[now].sum ;
t[now].lazy = t[now].lazy * f;
t[now].tag = 1;
}
inline void pushdown(int l, int r, int now)
{
int mid = (l + r) >> 1;
if(t[now].tag)
{
mark(lson, t[now].lazy);
if(r > mid) mark(rson, t[now].lazy);
t[now].lazy.I(), t[now].tag = 0;
}
}
void build(int l, int r, int now)
{
t[now].lazy.n = t[now].lazy.m = 2;
t[now].lazy.I();
t[now].tag = 0;
if(l == r)
{
t[now].sum = A[l];
return ;
}
int mid = (l + r) >> 1;
if(mid >= l) build(l, mid, lson);
if(r > mid) build(mid + 1, r, rson);
pushup(l, r, now);
}
void update(int l, int r, int now, int L, int R)
{
if(l >= L && r <= R)
{
mark(now , v);
return ;
}
pushdown(l, r, now);
int mid = (l + r) >> 1;
if(L <= mid) update(l, mid, lson, L, R);
if(R > mid) update(mid + 1, r, rson, L, R);
pushup(l, r, now);
}
ll query(int l, int r, int now, int L, int R)
{
if(l >= L && r <= R) return t[now].sum[1][0];
pushdown(l, r, now);
int mid = (l + r) >> 1;
ll g = 0;
if(L <= mid) g += query(l, mid, lson, L, R);
if(R > mid) g += query(mid + 1, r, rson, L, R);
return (g % mod);
}
int main()
{
// setIO("input");
init();
int i , j, x;
scanf("%d%d", &n, &m);
for(i = 1; i <= n ; ++i)
{
scanf("%d", &x), A[i] = (M ^ (x - 1)) * fib1;
}
build(1, n, 1);
for(int cas = 1, op , l, r, x; cas <= m ; ++cas)
{
scanf("%d", &op);
if(op == 1)
{
scanf("%d%d%d", &l, &r, &x);
if(x == 0) continue;
v = M ^ x;
update(1, n, 1, l, r);
}
if(op == 2)
{
scanf("%d%d", &l, &r);
printf("%lld\n", query(1, n, 1, l, r));
}
}
return 0;
}

  

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

  1. 【Codeforces718C】Sasha and Array 线段树 + 矩阵乘法

    C. Sasha and Array time limit per test:5 seconds memory limit per test:256 megabytes input:standard ...

  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. javaScript中==和===对数组、对象的判断是它们是否同一个实例对象

      问题描述 在实现业务时,大量用到了 if(a === b)这样的判断,但有一个类似判断一直进不去这个if条件, a === b 返回的一直是false,但是其他几个类似判断,都正常触发条件. 原因 ...

  2. [转帖]linux /proc目录下的文件为何无法用vi编辑保存

    linux /proc目录下的文件为何无法用vi编辑保存 https://blog.51cto.com/xlogin/1216914 学习一下 之前看过书 这一点 没太仔细看.. xlogin关注8人 ...

  3. Linux 下文件句柄数的查询学习

    1. 查看 所有进程的 打开的句柄数 lsof -n|awk '{print $2}'|sort|uniq -c |sort -nr|more 效果为: 2. 查看某一个进程内的 文件信息 lsof ...

  4. Python 把较长的一行代码分成多行的技巧

    概述:在写代码过程中,经常遇到一行代码很长的情况.为了让代码显得整齐干净,就需要把一行代码分成多行来写,Python中有三种小技巧可以实现该功能:        1.用反斜杠\链接多行代码 示例:   ...

  5. HNUSTOJ-1621 Picking Cabbage(状态压缩DP)

    1621: Picking Cabbage 时间限制: 2 Sec  内存限制: 32 MB提交: 26  解决: 14[提交][状态][讨论版] 题目描述 Once, Doraemon and  N ...

  6. HNUSTOJ-1512 奇怪的导弹(暴力)

    1512: 奇怪的导弹 时间限制: 3 Sec  内存限制: 32 MB提交: 31  解决: 13[提交][状态][讨论版] 题目描述 最近国际形势比较紧张,就拿中国来说,比如南海问题,钓鱼岛事件等 ...

  7. k路归并

    public static int[] k_merge(ArrayList<int[]> k_array) { if(CollectionUtils.isEmpty(k_array)){ ...

  8. 依据系统语言、设备、url 重定向对应页面

    1. 思路 获取浏览器语言.页面名称.区分手机端与电脑 根据特定方式命名 html 文件,然后独立文件,重定向 eg: - root -  gap.html     gap -    index.ht ...

  9. Inno setup 开源的安装包打包软件

    Inno Setup是一个开源的安装包打包软件,下载地址是:http://www.jrsoftware.org/isdl.php 使用引导界面创建一个安装包打包 配置参考官方文档:http://www ...

  10. Eclipse集成开发环境搭建

    gdbserver安装: 安装gdb-server的环境变量要放在arm-linux-gcc的环境的前面,因为arm-linux-gcc的安装包里面也有gdb,linux系统在找指令时从/root/. ...