题目链接: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. Taking a peek inside with the Actuator

    Taking a peek inside with the Actuator <dependency> <groupId>org.springframework.boot< ...

  2. sql中charindex的用法

    转自:https://www.cnblogs.com/beeone/p/3621743.html CHARINDEX和PATINDEX函数常常用来在一段字符中搜索字符或者字符串.如果被搜索的字符中包含 ...

  3. Why String is Immutable or Final in Java

    The string is Immutable in Java because String objects are cached in String pool. Since cached Strin ...

  4. javaScript高级教程(七)正则表达式中括号三种常见作用

    括号用来将子表达式标记起来,以区别于其他表达式 比如很多的命令行程序都提供帮助命令,键入 h 和键入 help 的意义是一样的,那么就会有这样的表达式: h(elp)? 字符h之后的elp可有可无这里 ...

  5. Window版本 安装mysql

    #1.下载:MySQL Community Server 5.7.16 http://dev.mysql.com/downloads/mysql/ 下载下来解压到指定目录 就安装完成了 #2.解压 如 ...

  6. mysql 数据操作 多表查询 多表连接查询 外链接之左连接 右连接

    1.外链接之左连接:优先显示左表全部记录   left join 在内连接的基础上保留左表的记录 即便左表有一条记录和右表没有关系,也把他留下 mysql> select * from empl ...

  7. NYOJ 47

    思路: 在n>3的时候就用前两个小的来带后两个大的,有两种方式(一就是1,2先过,然后1回来,然后n,n-1过,然后2,回来),(二就是 1,n先过去 然后1回来,然后 1,n-1过去吗.,然后 ...

  8. 让人抓狂的MySQL安装-8.0.12版本

    今天一个下午就做了一件事,把MySQL安装成功,安装的过程让人很狂躁.于是一边骂,一边查错,才把这个软件给安装成功了. 详细的安装步骤,这里就不赘述了.参见https://blog.csdn.net/ ...

  9. Ubuntu单用户模式(安全模式)

           说下我遇到的情况,ubuntu服务器,防火墙关闭,连的外网.服务器中毒,病毒自动生成用户,然后病毒进程开启启动,进程启动后,cpu立马占满,服务器立马卡死,本想着服务器启动后通过top命 ...

  10. SQL备份数据库代码

    SQL备份数据库代码 #region 服务每天备份一次数据库 /// <summary> /// 服务每天备份一次数据库 /// </summary> public void ...