题目链接:http://codeforces.com/problemset/problem/316/E3

题意:一个数列A三种操作:(1)1 x y将x位置的数字修改为y;(2)2 x y求[x,y]区间的数字的和,和函数为如下;(3)3 x y z将[x,y]区间的数字统一加z。

思路:很明显,这是一个线段树的题目。其中第一种和第三种操作都很容易搞定,第一种直接更新到底;第三种增加标记。显然为了求和,我们必须要在节点上增加一个和,表示以这个节点为根的子树的数字的和函数,这里我们用a来表示。那么,到这里有两件事情要解决:

(1)如何在区间增加一个值x时更新a?设该区间为[L,R],则增加的和为:

(2)已知两段数字的和函数,如何拼接成一个和函数?设前一段为3,后一段为4,那么我们要将后一段修改,修改前为:

修改后为:

为了方便,我们先看看怎么把(1,1,2,3)变为(1,2,3,5),也就是:

其实就是:

我们用a表示某段内(设这一段有x个数)x个数的和函数,b表示后x-1个数的和函数,那么上面其实就是a+b,得到A,那么B怎么得到呢?(AB和ab对应,我们发现B=a),因此我们得到转移矩阵:

注意这个的b和B是为了方便计算我们要新加到线段树节点中的值。那么上面(1,1,2,3)到(3,5,8,13)的转变岂不是成了:

到这里,我们就解决了两段和函数拼成一段的方法。

struct Matrix
{
    i64 a[2][2];

void init(int x)
    {
        clr(a,0);
        if(x==1) a[0][0]=a[1][1]=1;
        else if(x==2) a[0][0]=a[0][1]=a[1][0]=1;
    }

Matrix operator*(Matrix p)
    {
        Matrix ans;
        ans.init(0);
        int i,j,k;
        FOR0(k,2) FOR0(i,2) FOR0(j,2)
        {
            ans.a[i][j]+=a[i][k]*p.a[k][j];
            ans.a[i][j]%=mod;
        }
        return ans;
    }
};

Matrix A[N];
i64 f[N];

void init()
{
    A[0].init(1);
    A[1].init(2);
    int i;
    for(i=2;i<N;i++) A[i]=A[i-1]*A[1];

f[0]=f[1]=1;
    for(i=2;i<N;i++) f[i]=(f[i-1]+f[i-2])%mod;
    for(i=1;i<N;i++) f[i]=(f[i]+f[i-1])%mod;
}

struct node
{
    int L,R;
    i64 a,b,flag;

node(){}
    node(i64 _a,i64 _b)
    {
        a=_a;
        b=_b;
    }

node det(int t)
    {
        i64 x=(a*A[t].a[0][0]+b*A[t].a[0][1])%mod;
        i64 y=(a*A[t].a[1][0]+b*A[t].a[1][1])%mod;
        return node(x,y);
    }

void add(i64 x)
    {
        flag=(flag+x)%mod;
        a=(a+f[R-L]*x)%mod;
        if(R>L) b=(b+f[R-L-1]*x)%mod;
    }

node operator+(node p)
    {
        i64 x=(a+p.a)%mod,y=(b+p.b)%mod;
        return node(x,y);
    }
};

node a[N<<2];
int b[N];

void pushUp(int t)
{
    if(a[t].L==a[t].R) return;
    int mid=(a[t].L+a[t].R)>>1;
    node temp=a[t*2+1].det(mid-a[t].L+1);
    a[t].a=(a[t*2].a+temp.a)%mod;
    a[t].b=(a[t*2].b+temp.b)%mod;
}

void pushDown(int t)
{
    if(a[t].L==a[t].R) return;
    if(a[t].flag)
    {
        a[t*2].add(a[t].flag);
        a[t*2+1].add(a[t].flag);
        a[t].flag=0;
    }
}

void build(int t,int L,int R)
{
    a[t].L=L;
    a[t].R=R;
    a[t].flag=a[t].b=0;
    if(L==R)
    {
        a[t].a=b[L];
        return;
    }
    int mid=(a[t].L+a[t].R)>>1;
    build(t*2,L,mid);
    build(t*2+1,mid+1,R);
    pushUp(t);
}

void change(int t,int pos,int x)
{
    if(a[t].L==a[t].R)
    {
        a[t].a=x;
        a[t].b=0;
        a[t].flag=0;
        return;
    }
    pushDown(t);
    int mid=(a[t].L+a[t].R)>>1;
    if(pos<=mid) change(t*2,pos,x);
    else change(t*2+1,pos,x);
    pushUp(t);
}

void change(int t,int L,int R,int x)
{
    if(a[t].L==L&&a[t].R==R)
    {
        a[t].add(x);
        return;
    }
    pushDown(t);
    int mid=(a[t].L+a[t].R)>>1;
    if(R<=mid) change(t*2,L,R,x);
    else if(L>mid) change(t*2+1,L,R,x);
    else
    {
        change(t*2,L,mid,x);
        change(t*2+1,mid+1,R,x);
    }
    pushUp(t);
}

node query(int t,int L,int R)
{
    if(a[t].L==L&&a[t].R==R) return a[t];
    pushDown(t);
    node A,B;
    int mid=(a[t].L+a[t].R)>>1;
    if(R<=mid) A=query(t*2,L,R);
    else if(L>mid) A=query(t*2+1,L,R);
    else
    {
        A=query(t*2,L,mid);
        B=query(t*2+1,mid+1,R);
        A=A+B.det(mid-L+1);
    }
    pushDown(t);
    return A;
}

int n,m;

int main()
{
    init();
    Rush(n)
    {
        RD(m);
        int i;
        FOR1(i,n) RD(b[i]);
        build(1,1,n);
        int op,x,y,z;
        while(m--)
        {
            RD(op);
            if(op==1)
            {
                RD(x,y);
                change(1,x,y);
            }
            else if(op==2)
            {
                RD(x,y);
                PR(query(1,x,y).a);
            }
            else
            {
                RD(x,y,z);
                change(1,x,y,z);
            }
        }
    }
}

CF 316E3 Summer Homework(斐波那契矩阵+线段树)的更多相关文章

  1. Codeforces 446C - DZY Loves Fibonacci Numbers(斐波那契数列+线段树)

    Codeforces 题目传送门 & 洛谷题目传送门 你可能会疑惑我为什么要写 *2400 的题的题解 首先一个很明显的想法是,看到斐波那契数列和 \(10^9+9\) 就想到通项公式,\(F ...

  2. HDU 2855 斐波那契+矩阵快速幂

    http://acm.hdu.edu.cn/showproblem.php?pid=2855 化简这个公式,多写出几组就会发现规律 d[n]=F[2*n] 后面的任务就是矩阵快速幂拍一个斐波那契模板出 ...

  3. 「GXOI / GZOI2019」逼死强迫症——斐波那契+矩阵快速幂

    题目 [题目描述] ITX351 要铺一条 $2 \times N$ 的路,为此他购买了 $N$ 块 $2 \times 1$ 的方砖.可是其中一块砖在运送的过程中从中间裂开了,变成了两块 $1 \t ...

  4. 2018年湘潭大学程序设计竞赛G又见斐波那契(矩阵快速幂)

    题意 题目链接 Sol 直接矩阵快速幂 推出来的矩阵应该长这样 \begin{equation*}\begin{bmatrix}1&1&1&1&1&1\\1 & ...

  5. 以计算斐波那契数列为例说说动态规划算法(Dynamic Programming Algorithm Overlapping subproblems Optimal substructure Memoization Tabulation)

    动态规划(Dynamic Programming)是求解决策过程(decision process)最优化的数学方法.它的名字和动态没有关系,是Richard Bellman为了唬人而取的. 动态规划 ...

  6. 矩阵乘法&&矩阵快速幂&&最基本的矩阵模型——斐波那契数列

    矩阵,一个神奇又令人崩溃的东西,常常用来优化序列递推 在百度百科中,矩阵的定义: 在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合 ,最早来自于方程组的系数及常数所构成的方阵.这一 ...

  7. [Codeforces 316E3]Summer Homework(线段树+斐波那契数列)

    [Codeforces 316E3]Summer Homework(线段树+斐波那契数列) 顺便安利一下这个博客,给了我很大启发(https://gaisaiyuno.github.io/) 题面 有 ...

  8. codeforces316E3 Summer Homework(线段树,斐波那契数列)

    题目大意 给定一个n个数的数列,m个操作,有三种操作: \(1\ x\ v\) 将\(a_x\)的值修改成v $2\ l\ r\ $ 求 \(\sum_{i=l}^r x_i*f_{i-l}\) 其中 ...

  9. OptimalSolution(1)--递归和动态规划(1)斐波那契系列问题的递归和动态规划

    一.斐波那契数列 斐波那契数列就是:当n=0时,F(n)=0:当n=1时,F(n)=1:当n>1时,F(n) = F(n-1)+F(n-2). 根据斐波那契数列的定义,斐波那契数列为(从n=1开 ...

随机推荐

  1. pip freeze

    总结: 1.输出安装的包信息,并在另一个环境快速安装 Generate output suitable for a requirements file. $ pip freeze docutils== ...

  2. pip或easy_install安装库报错:SSL: CERTIFICATE_VERIFY_FAILED

    使用pip和easy_install安装那个lxml.pyspider这些库或者框架一直提示以下错误: Collecting pyspider Could not fetch URL https:// ...

  3. 一句替换bbcode

    $message=preg_replace('/\[[^\[\]]{1,}\]/','',$message);

  4. css 计算属性 calc的使用

    宽度等于父元素的宽度减去16像素 高度等于父元素的高度减去16像素 注意:100%和16px   与减号之间必须有空格,否则高度会失效!!!! .box{ width:calc(100% - 16px ...

  5. C++三大特性之封装

    原文地址:https://qunxinghu.github.io/2016/09/12/C++%20%E4%B8%89%E5%A4%A7%E7%89%B9%E6%80%A7%E4%B9%8B%E5%B ...

  6. kubernetes实战(十五):k8s使用helm持久化部署jenkins集成openLDAP登录

    1.基本概念 Jenkins在DevOps工具链中是核心的流程管理中心,负责串联系统的构建流程.测试流程.镜像制作流程.部署流程等,在持续集成中常用到的工具如下: Maven:源代码编译工具 Robo ...

  7. 据库被标记为RESTORING的处理方式,正在还原中,正在恢复

    关键词:正在还原,正在恢复,restoring,RECOVERING 转自:http://limindo.blog.163.com/blog/static/2647585620101161154121 ...

  8. 加密货币 (Cryptocurrency) 市值 (market capitalization) 列表

    https://coinmarketcap.com/all/views/all/ ico 列表 https://www.icoalert.com/?q=&is_v=1 https://www. ...

  9. python对象反射和函数反射

    python的对象反射功能,经常在编程时使用.相比较其它的编程语言使用非常方便.反射就是用字符串来操作对象或者类,模块中的成员. 一.对象的反射 反射功能的实现,由这4个内置函数来实现(hasattr ...

  10. Qt实现 QQ好友列表QToolBox

    简述 QToolBox类提供了一个列(选项卡式的)部件条目. QToolBox可以在一个tab列上显示另外一个,并且当前的item显示在当前的tab下面.每个tab都在tab列中有一个索引位置.tab ...