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

CF719E. Sasha and Array

题意:

对长度为 n 的数列进行 m 次操作, 操作为:

  1. a[l..r] 每一项都加一个常数 C, 其中 0 ≤ C ≤ 10^9
  2. 求 F[a[l]]+F[a[l+1]]+...F[a[r]] mod 1e9+7 的余数


矩阵快速幂求斐波那契

矩阵满足乘法分配律和结合律!

所以可以每个节点维护矩阵/矩阵和,区间加相当于区间乘矩阵

注意:不要把快速幂写在里面,复杂度平添一个log。把\(B^C\)算出来之后传进去就好了

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
#define lc x<<1
#define rc x<<1|1
#define mid ((l+r)>>1)
#define lson lc, l, mid
#define rson rc, mid+1, r
const int N = 1e5+5, P = 1e9+7;

int n, m;
struct Matrix {
    ll a[2][2];
    ll* operator [](int x) {return a[x];}
    Matrix(int p=0) {
        if(!p) a[0][0] = a[0][1] = a[1][0] = a[1][1] = 0;
        else a[0][0] = a[1][1] = 1, a[0][1] = a[1][0] = 0;
    }
} B;

Matrix operator + (Matrix a, Matrix b) {
    Matrix c;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            c[i][j] = (a[i][j] + b[i][j]) %P;
    return c;
}

Matrix operator * (Matrix a, Matrix b) {
    Matrix c;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++) {
            ll &x = c[i][j];
            for(int k=0; k<2; k++)
                x = (x + a[i][k] * b[k][j] %P) %P;
        }
    return c;
}

Matrix operator ^ (Matrix a, int b) {
    Matrix ans(1);
    ans[0][0] = ans[1][1] = 1;
    for(; b; b>>=1, a=a*a)
        if(b & 1) ans = ans*a;
    return ans;
}

struct meow {
    Matrix f;
    Matrix v;
    int c;
    meow() {f[0][0] = 1; v[0][0] = v[1][1] = 1;}
} t[N<<2];

void paint(int x, int l, int r, int d, Matrix &v) {
    t[x].c += d;
    t[x].v = v * t[x].v;
    t[x].f = v * t[x].f;
}
void push_down(int x, int l, int r) {
    if(t[x].c) {
        paint(lson, t[x].c, t[x].v);
        paint(rson, t[x].c, t[x].v);
        t[x].c = 0;
        t[x].v = Matrix(1);
    }
}
void merge(int x) {
    t[x].f = t[lc].f + t[rc].f;
}

void build(int x, int l, int r) {
    if(l == r) {
        cin >> t[x].c;
        if(t[x].c > 1) t[x].f = (B ^ (t[x].c - 1)) * t[x].f;
    } else {
        build(lson);
        build(rson);
        merge(x);
    }
}

void Add(int x, int l, int r, int ql, int qr, int d, Matrix &v) {
    if(ql <= l && r <= qr) paint(x, l, r, d, v);
    else {
        push_down(x, l, r);
        if(ql <= mid) Add(lson, ql, qr, d, v);
        if(mid < qr)  Add(rson, ql, qr, d,v );
        merge(x);
    }
}

ll Que(int x, int l, int r, int ql, int qr) {
    if(ql <= l && r <= qr) return t[x].f[0][0];
    else {
        push_down(x, l, r);
        ll ans = 0;
        if(ql <= mid) ans = (ans + Que(lson, ql, qr)) %P;
        if(mid < qr)  ans = (ans + Que(rson, ql, qr)) %P;
        return ans;
    }
}

int main() {
    //freopen("in", "r", stdin);
    ios::sync_with_stdio(false); cin.tie(); cout.tie();

    B[0][0] = B[0][1] = B[1][0] = 1;
    cin >> n >> m;
    build(1, 1, n);

    for(int i=1; i<=m; i++) {
        int tp, l, r, x;
        cin >> tp >> l >> r;
        if(tp == 1) {
            cin >> x;
            Matrix t = B^x;
            Add(1, 1, n, l, r, x, t);
        } else cout << Que(1, 1, n, l, r) << '\n';
    }

原文地址:https://www.cnblogs.com/candy99/p/9319886.html

时间: 2024-10-10 21:10:47

CF719E. Sasha and Array [线段树维护矩阵]的相关文章

codeforces CF718C Sasha and Array 线段树维护矩阵

$ \Rightarrow $ 戳我进CF原题 C. Underground Lab time limit per test: 1 second memory limit per test: 256 megabytes input: standard input output: standard output The evil Bumbershoot corporation produces clones for gruesome experiments in a vast undergroun

CF718C Sasha and Array(线段树维护矩阵)

题解 (不会矩阵加速的先去学矩阵加速) 反正我想不到线段树维护矩阵.我太菜了. 我们在线段树上维护一个区间的斐波那契的列矩阵的和. 然后询问时提取每个符合题意列矩阵的答案项(不是列矩阵存了两项吗,一个是当前项,一个是用来递推的) 因为矩阵乘有结合律所以区间加这个操作就直接区间乘变换矩阵的x次方就行. 然后记得开long long 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include&

Subsequence Count 2017ccpc网络赛 1006 dp+线段树维护矩阵

Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string.There are two types of queries:1. Flipping the bits (i.e., changing all 1 to 0 and 0 to 1) between l and r (inclusive).2. Counting the

HDU 6155 Subsequence Count 线段树维护矩阵

Subsequence Count Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others) Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string. There are two types of querie

[动态dp]线段树维护转移矩阵

背景:czy上课讲了新知识,从未见到过,总结一下. 所谓动态dp,是在动态规划的基础上,需要维护一些修改操作的算法. 这类题目分为如下三个步骤:(都是对于常系数齐次递推问题) 1先不考虑修改,不考虑区间,直接列出整个区间的dp方程.这个是基础,动态dp无论如何还是dp(这一步是一般是重点) 2.列出转移矩阵.由于有很多修改操作,我们将数据集中在一起处理,还可以利用矩阵结合律,并且区间比较好提取,(找一段矩阵就好了),修改也方便. 3.线段树维护矩阵.对于修改,我们就是在矩阵上进行修改,对于不同的

HDU 5068 Harry And Math Teacher( 矩阵乘法 + 线段树维护 )

HDU 5068 Harry And Math Teacher( 矩阵乘法 + 线段树维护 ) 题意: 首先是这题题意理解错误,,其次是这题无法理解状态... 已经不是英文有多烂的情况了,是中文没学好啊.....大学不学语文才是真正的硬伤啊 题目意思 有一个城堡有很多层楼, 每层楼有2个门,每个门里面又有两个楼梯,可以通往上一层的两个门 问,从x层楼到y层楼有多少中方法(不能返回) 具体看图吧,,,已经不会说话了 1 #include <cstdio> 2 #include <cstri

2016shenyang-1002-HDU5893-List wants to travel-树链剖分+线段树维护不同区间段个数

肯定先无脑树链剖分,然后线段树维护一段区间不同个数,再维护一个左右端点的费用. 线段树更新,pushDown,pushUp的时候要注意考虑链接位置的费用是否相同 还有就是树链剖分操作的时候,维护上一个更新的位置的费用. 总之就是出现区间合并,就考虑总数是否要减一 好想不好写 //场上根本写不完啊 1 /*--------------------------------------------------------------------------------------*/ 2 3 #inc

Codeforces 482B Interesting Array(线段树)

题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,现在有M个限制,每个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 否有满足的数列. 解题思路:线段树维护,每条限制等于是对l~r之间的数或上q(取且的性质,相应二进制位一定为1),那么处理完所有的 限制,在进行查询,查询对应每个l~r之间的数取且是否还等于q.所以用线段树维护取且和,修改为或操作. #include <cstdio> #include <c

从《楼房重建》出发浅谈一类使用线段树维护前缀最大值的算法

首先需要申明的是,真的是浅谈,因为我对这个算法的认识还是非常低的. 既然是从<楼房重建>出发,那么当然是先看看这道题: [清华集训2013]楼房重建 bzoj 链接 题意简述: 有 \(n\) 栋楼,第 \(i\) 栋的高度为 \(H_i\),也就是说第 \(i\) 栋楼可以抽象成一条两端点为 \((i, 0)\) 和 \((i, H_i)\) 的线段. 初始时 \(H_i\) 均为 \(0\),要支持动态修改单点的 \(H_i\). 每次询问从 \(O(0, 0)\) 点可以看到多少栋楼房.