[CF718C]Sasha and Array

718C:Sasha and Array

题意简述

维护一个长度为 n 的数列a,支持下面两个操作:
1. al ar 加上 x
2.询问ri=lfib(ai) 109+7 的值,其中 fib(x) 表示斐波那契数列的第 x
询问数m

数据范围

1n,m105
1ai,x109

思路

线段树维护斐波那契的转移矩阵。
我们的1操作就相当于是区间乘上这个矩阵。
因为矩阵满足乘法对加法的分配律。
所以父亲记录了两个孩子矩阵的和。
用一个矩阵当做标记,可以避免每次pushdown的时候都要计算一次快速幂,复杂度少一个log。
整体复杂度 O(23nlogn)

代码

#include<cstdio>
#include<cstring>
using namespace std;
const int p=1000000007;
struct Matrix{
    int x,y;
    int d[2][2];
    Matrix(){};
    Matrix (int _x,int _y)
    {
        x=_x,y=_y;
        memset(d,0,sizeof(d));
    }
    Matrix operator * (const Matrix &n1)
    {
        Matrix ret(x,n1.y);
        for (int i=0;i<x;i++)
            for (int j=0;j<y;j++)
                for (int k=0;k<n1.y;k++)
                    ret.d[i][k]=(ret.d[i][k]+1LL*d[i][j]*n1.d[j][k])%p;
        return ret;
    }
    Matrix operator + (const Matrix &n1)
    {
        Matrix ret(x,y);
        for (int i=0;i<x;i++)
            for (int j=0;j<y;j++)
                ret.d[i][j]=(d[i][j]+n1.d[i][j])%p;
        return ret;
    }
    Matrix pow(int ff)
    {
        Matrix ret(x,y);
        ret.d[0][0]=ret.d[1][1]=1;
        Matrix sum=*this;
        while (ff)
        {
            if (ff&1)
                ret=ret*sum;
            sum=sum*sum;
            ff/=2;
        }
        return ret;
    }
}base(2,2),tmp(2,2);
int n,m,u,v,w,opt;
int seq[100010];
namespace Segtree
{
    struct Node{
        Matrix data,add;
        void modify_add(Matrix &val)
        {
            add=add*val;
            data=data*val;
        }
    };

    Node tree[400010];
    void pushup(int node)
    {
        tree[node].data=tree[node<<1].data+tree[node<<1|1].data;
    }
    bool is_0(Matrix &val)
    {
        return (val.d[0][0]==1&&val.d[0][1]==0&&val.d[1][0]==0&&val.d[1][1]==1);
    }

    void pushdown(int node)
    {
        if (!is_0(tree[node].add))
        {
            tree[node<<1].modify_add(tree[node].add);
            tree[node<<1|1].modify_add(tree[node].add);
            tree[node].add.d[0][0]=tree[node].add.d[1][1]=1;
            tree[node].add.d[0][1]=tree[node].add.d[1][0]=0;
        }
    }
    void build(int l,int r,int node)
    {
        tree[node].add=base.pow(0);
        if (l==r)
        {
            tree[node].data=base.pow(seq[l]-1);
            return;
        }
        int mid=(l+r)>>1;
        build(l,mid,node<<1);
        build(mid+1,r,node<<1|1);
        pushup(node);
    }
    void modify_add(int L,int R,int l,int r,int node,Matrix &val)
    {
        if (L<=l&&r<=R)
        {
            tree[node].modify_add(val);
            return;
        }
        pushdown(node);
        int mid=(l+r)>>1;
        if (L<=mid)
            modify_add(L,R,l,mid,node<<1,val);
        if (R>mid)
            modify_add(L,R,mid+1,r,node<<1|1,val);
        pushup(node);
    }
    int query(int L,int R,int l,int r,int node)
    {
        if (L<=l&&r<=R)
            return (tree[node].data.d[0][0]+tree[node].data.d[1][0])%p;
        pushdown(node);
        int ret=0;
        int mid=(l+r)>>1;
        if (L<=mid)
            ret=(ret+query(L,R,l,mid,node<<1))%p;
        if (R>mid)
            ret=(ret+query(L,R,mid+1,r,node<<1|1))%p;
        return ret;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&seq[i]);
    base.d[0][0]=0;
    base.d[1][1]=base.d[0][1]=base.d[1][0]=1;
    Segtree::build(1,n,1);
    tmp=base.pow(0);
    for (int i=1;i<=m;i++)
    {
        scanf("%d",&opt);
        if (opt==1)
        {
            scanf("%d%d%d",&u,&v,&w);
            tmp=base.pow(w);
            Segtree::modify_add(u,v,1,n,1,tmp);
        }
        if (opt==2)
        {
            scanf("%d%d",&u,&v);
            printf("%d\n",Segtree::query(u,v,1,n,1));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值