CodeForces 718C Sasha and Array

线段树。

线段树维护区间矩阵和,操作都是最简单的线段树。$lazy$标记不要记录乘了几次,直接记录乘了几次之后的矩阵就可以了,不然每次下传的时候再算一遍时间复杂度会提高。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<bitset>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-6;
void File()
{
    freopen("D:\in.txt","r",stdin);
    freopen("D:\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
    char c=getchar(); x=0;
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) {x=x*10+c-'0'; c=getchar();}
}

int mod=1e9+7;
const int maxn=100010;
struct Matrix
{
    int A[3][3]; int R,C;
}s[4*maxn],t[4*maxn];
int n,m;
Matrix Q,Z,P;

Matrix ch(Matrix a,Matrix b)
{
    Matrix c;
    int i, j, k;
    for (i = 1; i <= a.R; i++)
        for (j = 1; j <= b.C; j++){
            c.A[i][j]=0;
            for (k = 1; k <= a.C; k++){
                LL aa=(LL)a.A[i][k],bb=(LL)b.A[k][j];
                LL cc=aa*bb%(LL)mod;
                int dd=(int)cc;
                c.A[i][j] = (c.A[i][j] + dd)%mod;
            }
        }
    c.R=a.R; c.C=b.C;
    return c;
}

Matrix pow(LL p)
{
    Matrix X,Y;

    X.R=2; X.C=2; Y.R=2; Y.C=2;

    Y.A[1][1]=1; Y.A[1][2]=0;
    Y.A[2][1]=0; Y.A[2][2]=1;

    X.A[1][1]=0; X.A[1][2]=1;
    X.A[2][1]=1; X.A[2][2]=1;

    while (p)
    {
        if (p % 2 == 1) Y = ch(Y,X);
        p = p >> 1;
        X = ch(X,X);
    }
    return Y;
}

void pushUp(int rt)
{
    s[rt].R=2; s[rt].C=2;
    s[rt].A[1][1]=(s[2*rt].A[1][1]+s[2*rt+1].A[1][1])%mod;
    s[rt].A[1][2]=(s[2*rt].A[1][2]+s[2*rt+1].A[1][2])%mod;
    s[rt].A[2][1]=(s[2*rt].A[2][1]+s[2*rt+1].A[2][1])%mod;
    s[rt].A[2][2]=(s[2*rt].A[2][2]+s[2*rt+1].A[2][2])%mod;
}

bool check(Matrix x)
{
    if(x.A[1][1]!=1) return 0;
    if(x.A[1][2]!=0) return 0;
    if(x.A[2][1]!=0) return 0;
    if(x.A[2][2]!=1) return 0;
    return 1;
}

void pushDown(int rt)
{
    if(check(t[rt])==1) return;

    s[2*rt]=ch(s[2*rt],t[rt]); t[2*rt]=ch(t[2*rt],t[rt]);
    s[2*rt+1]=ch(s[2*rt+1],t[rt]); t[2*rt+1]=ch(t[2*rt+1],t[rt]);

    t[rt].A[1][1]=1; t[rt].A[1][2]=0;
    t[rt].A[2][1]=0; t[rt].A[2][2]=1;
}

void build(int l,int r,int rt)
{
    t[rt].A[1][1]=1; t[rt].A[1][2]=0;
    t[rt].A[2][1]=0; t[rt].A[2][2]=1;
    t[rt].R=2; t[rt].C=2;

    if(l==r)
    {
        LL x; scanf("%lld",&x);

        s[rt].R=2; s[rt].C=2;
        s[rt].A[1][1]=1; s[rt].A[1][2]=0;
        s[rt].A[2][1]=0; s[rt].A[2][2]=1;

        s[rt]=ch(s[rt],pow(x-1));
        return;
    }

    int m=(l+r)/2;
    build(l,m,2*rt);
    build(m+1,r,2*rt+1);
    pushUp(rt);
}

void update(int L,int R,LL x,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        s[rt]=ch(s[rt],P);
        t[rt]=ch(t[rt],P);
        return ;
    }

    int m=(l+r)/2;
    pushDown(rt);
    if(L<=m) update(L,R,x,l,m,2*rt);
    if(R>m) update(L,R,x,m+1,r,2*rt+1);
    pushUp(rt);
}

void add(Matrix a)
{
    Q.A[1][1]=(Q.A[1][1]+a.A[1][1])%mod;
    Q.A[1][2]=(Q.A[1][2]+a.A[1][2])%mod;
    Q.A[2][1]=(Q.A[2][1]+a.A[2][1])%mod;
    Q.A[2][2]=(Q.A[2][2]+a.A[2][2])%mod;
}

void get(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) { add(s[rt]); return ; }

    int m=(l+r)/2;
    pushDown(rt);
    if(L<=m) get(L,R,l,m,2*rt);
    if(R>m) get(L,R,m+1,r,2*rt+1);
    pushUp(rt);
}

int main()
{
    scanf("%d%d",&n,&m);
    build(1,n,1);
    for(int i=1;i<=m;i++)
    {
        int op; scanf("%d",&op);
        int L,R; scanf("%d%d",&L,&R);
        if(op==1)
        {
            LL x; scanf("%lld",&x);
            P=pow(x); update(L,R,x,1,n,1);
        }
        else
        {
            Q.R=2; Q.C=2; memset(Q.A,0,sizeof Q.A);
            get(L,R,1,n,1);
            Z.R=1; Z.C=2; Z.A[1][1]=1; Z.A[1][2]=1;
            Z=ch(Z,Q);
            printf("%d
",Z.A[1][1]);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/5922310.html