Codeforces Round #373 div1 C-Sasha and Array(線段樹維護矩陣 矩陣快速冪)

題目鏈接


題意

給一個數組,值表示第x個斐波那契數。有兩個操作:

區間求和:對區間的值求相應的斐波那契數,然後求和

區間修改:對區間範圍的數都加上y(代表的斐波那契數的下標往後加y個)

 假設f[0] = 0,f[1] = 1 ,f[2] = 2 。。。。然後求第k個斐波那契數就相當於把2*2的矩陣[ [1 1] [1 0] ]自乘k-1次,求m[0][0]就是了。

 

線段樹維護矩陣,lazy標記也是一個矩陣。其他和普通的區間修改線段樹沒啥區別。


#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int N = 1e5+10;
const int mod = 1e9+7;
int n,k;
int arr[N];

struct Matrix
{
    ll m[2][2];
    friend Matrix operator*(const Matrix& a,const Matrix& b){
        Matrix t;
        for(int i=0;i<2;i++){
            for(int j=0;j<2;j++){
                int sum = 0;
                for(int k=0;k<2;k++){
                    sum += (a.m[i][k])*(b.m[k][j])%mod;
                t.m[i][j] = sum%mod;
                }
            }
        }
        return t;
    }
    friend Matrix operator+(const Matrix& a,const Matrix& b){
        Matrix t;
        for(int i=0;i<2;i++){
            for(int j=0;j<2;j++){
                t.m[i][j] = (a.m[i][j]+b.m[i][j])%mod;
            }
        }
        return t;
    }
    void init(){
        m[0][0] = m[1][1] = 1;
        m[0][1] = m[1][0] = 0;
    }
};

struct node
{
    int l,r,k;
    Matrix sum,lazy;
}tr[N<<2];

Matrix qpow(int k)
{
    Matrix ans,a;
    memset(ans.m,0,sizeof(ans.m));
    for(int i=0;i<2;i++)
		ans.m[i][i] = 1;
    a.m[0][0] = a.m[1][0] = a.m[0][1] = 1;
    a.m[1][1] = 0;
    while(k)
    {
        if(k&1) ans = ans*a;
        a = a*a;
        k>>=1;
    }
    return ans;
}

void build(int k,int l,int r)
{
    tr[k].l = l; tr[k].r = r; tr[k].sum.init();tr[k].lazy.init();
    if(l==r){
        tr[k].sum = qpow(arr[l]-1);
        return;
    }
    int mid = (l+r)/2;
    build(k*2,l,mid);
    build(k*2+1,mid+1,r);
    tr[k].sum = tr[k*2].sum + tr[k*2+1].sum;
}

void pushdown(int k)
{
    tr[k*2].sum = tr[k*2].sum*tr[k].lazy;
    tr[k*2+1].sum = tr[k*2+1].sum*tr[k].lazy;
    tr[k*2].lazy = tr[k*2].lazy*tr[k].lazy;
    tr[k*2+1].lazy = tr[k*2+1].lazy*tr[k].lazy;
    tr[k].lazy.init();
}

void update(int k,int l,int r,Matrix v)
{
    if(tr[k].l>=l&&tr[k].r<=r){
        tr[k].sum = tr[k].sum*v;
        tr[k].lazy = tr[k].lazy*v;
        return;
    }
    pushdown(k);
    int mid = (tr[k].l+tr[k].r)/2;
    if(l<=mid) update(k*2,l,r,v);
    if(r>mid) update(k*2+1,l,r,v);
    tr[k].sum = tr[k*2].sum + tr[k*2+1].sum;
}

ll query(int k,int l,int r)
{

    if(tr[k].l>=l&&tr[k].r<=r) return tr[k].sum.m[0][0];
    pushdown(k);
    int mid = (tr[k].l+tr[k].r)/2;
    ll res = 0;
    if(l<=mid) res = (res + query(k*2,l,r))%mod;
    if(r>mid) res = (res + query(k*2+1,l,r))%mod;
    tr[k].sum = tr[k*2].sum + tr[k*2+1].sum;
    return res;
}

int main()
{
    int n,m; scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&arr[i]);
    build(1,1,n);
    while(m--){
        int op,x,y;scanf("%d%d%d",&op,&x,&y);
        if(op==1){
            int t; scanf("%d",&t);
            Matrix c = qpow(t);
            update(1,x,y,c);
        }
        else{
            printf("%I64d\n",query(1,x,y));
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章