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

来源:互联网 发布:unity3d 刚体穿透 编辑:程序博客网 时间:2024/05/22 12:59

题目:点击打开链接

题意:给出有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 longconst 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
原创粉丝点击