Sasha and Array CodeForces - 719E

http://codeforces.com/problemset/problem/719/E

像等差数列一样 斐波那契数列也满足可加性 所以每个区间只维护前两项即可 给每个区间项数加x等于对每个点把斐波那契矩阵乘x次 线段树里维护前两项 并把laz标记做成矩阵形式即可

一开始智障 把x当参数传进update 每遇到一次目标区间就要做一次矩阵快速幂 喜获一T

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
const ll M=1000000007;

struct node
{
    int l;
    int r;
    ll f1;
    ll f2;
    ll laz[2][2];
};

node tree[800010];
ll mat[2][2];
int n,q;

void getmul(ll a[][2],ll b[][2])
{
    ll t[2][2];
    int i,j,k;
    for(i=0;i<2;i++)
    {
        for(j=0;j<2;j++)
        {
            t[i][j]=0;
            for(k=0;k<2;k++)
            {
                t[i][j]=(t[i][j]+(a[i][k]*b[k][j])%M)%M;
            }
        }
    }
    memcpy(a,t,sizeof(t));
}

void quickpow(ll x)
{
    ll tmp[2][2];
    mat[0][0]=1,mat[0][1]=0;
    mat[1][0]=0,mat[1][1]=1;
    tmp[0][0]=1,tmp[0][1]=1;
    tmp[1][0]=1,tmp[1][1]=0;
    while(x>0)
    {
        if(x%2) getmul(mat,tmp);
        x/=2,getmul(tmp,tmp);
    }
}

bool judge(ll gou[][2])
{
    if(gou[0][0]==1&&gou[0][1]==0&&gou[1][0]==0&&gou[1][1]==1) return true;
    else return false;
}

void init(ll gou[][2])
{
    gou[0][0]=1,gou[0][1]=0;
    gou[1][0]=0,gou[1][1]=1;
}

void pushup(int cur)
{
    tree[cur].f1=(tree[2*cur].f1+tree[2*cur+1].f1)%M;
    tree[cur].f2=(tree[2*cur].f2+tree[2*cur+1].f2)%M;
}

void pushdown(int cur)
{
    ll t1,t2;
    if(!judge(tree[cur].laz))
    {
        t1=((tree[cur].laz[1][0]*tree[2*cur].f2)%M+(tree[cur].laz[1][1]*tree[2*cur].f1)%M)%M;
        t2=((tree[cur].laz[0][0]*tree[2*cur].f2)%M+(tree[cur].laz[0][1]*tree[2*cur].f1)%M)%M;
        tree[2*cur].f1=t1,tree[2*cur].f2=t2;
        getmul(tree[2*cur].laz,tree[cur].laz);

        t1=((tree[cur].laz[1][0]*tree[2*cur+1].f2)%M+(tree[cur].laz[1][1]*tree[2*cur+1].f1)%M)%M;
        t2=((tree[cur].laz[0][0]*tree[2*cur+1].f2)%M+(tree[cur].laz[0][1]*tree[2*cur+1].f1)%M)%M;
        tree[2*cur+1].f1=t1,tree[2*cur+1].f2=t2;
        getmul(tree[2*cur+1].laz,tree[cur].laz);

        init(tree[cur].laz);
    }
}

void build(int l,int r,int cur)
{
    ll x;
    int m;
    tree[cur].l=l;
    tree[cur].r=r;
    tree[cur].laz[0][0]=1,tree[cur].laz[0][1]=0;
    tree[cur].laz[1][0]=0,tree[cur].laz[1][1]=1;
    if(l==r)
    {
        scanf("%lld",&x);
        if(x==1) tree[cur].f1=1,tree[cur].f2=1;
        else
        {
            quickpow(x-1);
            tree[cur].f1=(mat[1][0]+mat[1][1])%M;
            tree[cur].f2=(mat[0][0]+mat[0][1])%M;
        }
        return;
    }
    m=(l+r)/2;
    build(l,m,2*cur);
    build(m+1,r,2*cur+1);
    pushup(cur);
}

void update(int pl,int pr,int cur)
{
    ll t1,t2;
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        t1=((mat[1][0]*tree[cur].f2)%M+(mat[1][1]*tree[cur].f1)%M)%M;
        t2=((mat[0][0]*tree[cur].f2)%M+(mat[0][1]*tree[cur].f1)%M)%M;
        tree[cur].f1=t1,tree[cur].f2=t2;
        getmul(tree[cur].laz,mat);
        return;
    }
    pushdown(cur);
    if(pl<=tree[2*cur].r) update(pl,pr,2*cur);
    if(pr>=tree[2*cur+1].l) update(pl,pr,2*cur+1);
    pushup(cur);
}

ll query(int pl,int pr,int cur)
{
    ll res;
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        return tree[cur].f1;
    }
    pushdown(cur);
    res=0;
    if(pl<=tree[2*cur].r) res=(res+query(pl,pr,2*cur))%M;
    if(pr>=tree[2*cur+1].l) res=(res+query(pl,pr,2*cur+1))%M;
    return res;
}

int main()
{
    ll x;
    int op,l,r;
    scanf("%d%d",&n,&q);
    build(1,n,1);
    while(q--)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d%lld",&l,&r,&x);
            quickpow(x);
            update(l,r,1);
        }
        else
        {
            scanf("%d%d",&l,&r);
            printf("%lld\n",query(l,r,1));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sunyutian1998/article/details/81274356
今日推荐