CodeForces 719E Sasha and Array 【线段树】【快速矩阵幂】

题目:点击打开链接

题意:给出有n个元素的数列ai(1<=i<=n)以及m次操作,操作分为两种:①将区间[l,r]的数加x;②询问∑f(ai)(l<=i<=r),其中f(x)是斐波那契数列的第x个数

分析:容易想到用快速矩阵幂求斐波那契数列,同时用线段树储存和矩阵以及lazy矩阵,如果lazy标记为指数的话每次更新都要用一遍快速矩阵幂,就会超时。因为矩阵乘法满足分配律,且区间[l,r]加上x可以表示为乘上x次q矩阵,所以线段树维护矩阵之和,同时每次更新的时候,x可以先用快速矩阵幂,求出变换x次后的矩阵,然后在线段树中更新,即和矩阵和lazy矩阵乘上该矩阵,表示加上区间的数加上x后的斐波那契数之和了。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define sqr(x) ((x)*(x))
#define PR pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const ll INF = 3e18;
const int inf=0x3f3f3f3f;
const int M=100010;
const int N=100010;
const int Matsize=2;
const ll MOD=1000000007;
const double eps=1e-3;
const double pi=acos(-1.0);
using namespace std;
struct Mat
{
    ll mat[Matsize][Matsize];
    void init()
    {
        for(int i=0;i<Matsize;i++)
        {
            for(int j=0;j<Matsize;j++) mat[i][j]=0;
            mat[i][i]=1;
        }
    }
    Mat operator*(const Mat &t)const
    {
        Mat ans;
        memset(ans.mat,0,sizeof(ans.mat));
        for(int k=0;k<Matsize;k++)
            for(int i=0;i<Matsize;i++)
                for(int j=0;j<Matsize;j++)
                    ans.mat[i][j]=(ans.mat[i][j]+mat[i][k]*t.mat[k][j])%MOD;
        return ans;
    }
    Mat operator+(const Mat &t)const
    {
        Mat ans;
        for(int i=0;i<Matsize;i++)
            for(int j=0;j<Matsize;j++)
                ans.mat[i][j]=(mat[i][j]+t.mat[i][j])%MOD;
        return ans;
    }
};
int n,m,op,l,r;
Mat a[N<<2],lazy[N<<2],mt;
ll x;
Mat pow_M(ll m)
{
    Mat res;
    res.init();
    mt.mat[0][0]=mt.mat[0][1]=mt.mat[1][0]=1,mt.mat[1][1]=0;
    while(m)
    {
        if(m&1) res=res*mt;
        mt=mt*mt;
        m>>=1;
    }
    return res;
}
void pushup(int rt)
{
    a[rt]=a[rt<<1]+a[rt<<1|1];
}
void pushdown(int rt)
{
    lazy[rt<<1]=lazy[rt<<1]*lazy[rt];
    lazy[rt<<1|1]=lazy[rt<<1|1]*lazy[rt];
    a[rt<<1]=a[rt<<1]*lazy[rt];
    a[rt<<1|1]=a[rt<<1|1]*lazy[rt];
    lazy[rt].init();
}
void build(int l,int r,int rt)
{
    a[rt].init();
    lazy[rt].init();
    if(l==r)
    {
        ll t;
        scanf("%I64d",&t);
        a[rt]=pow_M(t-1);
        return;
    }
    int m=l+r>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int L,int R,Mat x,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        a[rt]=a[rt]*x;
        lazy[rt]=lazy[rt]*x;
        return;
    }
    pushdown(rt);
    int m=l+r>>1;
    if(L<=m) update(L,R,x,lson);
    if(m<R) update(L,R,x,rson);
    pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) return a[rt].mat[0][0];
    pushdown(rt);
    int m=l+r>>1;
    ll res=0;
    if(L<=m) res=(res+query(L,R,lson))%MOD;
    if(m<R) res=(res+query(L,R,rson))%MOD;
    return res;
}
int main()
{
    scanf("%d%d",&n,&m);
    build(1,n,1);
    while(m--)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d%I64d",&l,&r,&x);
            Mat t=pow_M(x);
            update(l,r,t,1,n,1);
        }
        else
        {
            scanf("%d%d",&l,&r);
            printf("%I64d\n",query(l,r,1,n,1));
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值