CF718C Sasha and Array(线段树+矩阵乘法)

根据斐波那契的性质得出,区间存在结合律,因此我们对于原先给定的先建出线段树,对每个点维护一个矩阵表示当前的斐波那契答案。

对于opt1,就是区间修改,也就是加上一个转移矩阵,传递这个矩阵,与普通的线段树操作一样的

对于opt2.也就是区间查询,查询区间内的和,因此我们只需要维护一个sum矩阵和lazy矩阵即可。

本题设计到的操作都需要进行重载运算符

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+10;
const int mod=1e9+7;
struct MA{
    ll a[3][3];
    MA(){
        memset(a,0,sizeof a);
    }
}P,Q,I;
struct node{
    int l,r;
    MA sum;
    MA lazy;
}tr[N<<2];
int n,m;
int a[N];
void init(){
    P.a[0][0]=1,P.a[0][1]=P.a[1][0]=P.a[1][1]=0;//状态矩阵
    Q.a[0][0]=Q.a[0][1]=Q.a[1][0]=1,Q.a[1][1]=0;//转移矩阵
    I.a[0][0]=I.a[1][1]=1,I.a[1][0]=I.a[0][1]=0;//单位矩阵
}
MA operator *(MA a,MA b) {
    MA tmp;
    for(int i=0;i<2;i++) {
        for(int j=0;j<2;j++) {
            for(int k=0;k<2;k++) {
                tmp.a[i][j]=((ll)tmp.a[i][j]+(ll)a.a[i][k]*b.a[k][j]%mod)%mod;
            }
        }
    }
    return tmp;
}
MA operator+(MA a,MA b){
    MA tmp;
    int i,j;
    for(i=0;i<2;i++){
        for(j=0;j<2;j++)
            tmp.a[i][j]=(a.a[i][j]+b.a[i][j])%mod;
    }
    return tmp;
}
bool operator !=(MA a,MA b){
    int i,j;
    for(i=0;i<2;i++){
        for(j=0;j<2;j++){
            if(a.a[i][j]!=b.a[i][j])
                return true;
        }
    }
    return false;
}
MA qpow(MA a,int i) {
    MA b;
    for(int i=0;i<2;i++) b.a[i][i]=1;
    while(i) {
        if(i&1) b=b*a;
        a=a*a;
        i>>=1;
    }
    return b;
}
void pushup(int u){
    tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void build(int u,int l,int r){
    if(l==r){
        tr[u]={l,r,qpow(Q,a[l]-1),I};
    }
    else{
        tr[u]={l,r,I,I};
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
void pushdown(int u){
    tr[u<<1].sum=tr[u<<1].sum*tr[u].lazy;
    tr[u<<1|1].sum=tr[u<<1|1].sum*tr[u].lazy;
    tr[u<<1].lazy=tr[u<<1].lazy*tr[u].lazy;
    tr[u<<1|1].lazy=tr[u<<1|1].lazy*tr[u].lazy;
    tr[u].lazy=I;
}
void modify(int u,int l,int r,MA x){
    if(tr[u].l>=l&&tr[u].r<=r){
        tr[u].sum=tr[u].sum*x;
        tr[u].lazy=tr[u].lazy*x;
        return ;
    }
    if(tr[u].lazy!=I)
        pushdown(u);
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid)
        modify(u<<1,l,r,x);
    if(r>mid)
        modify(u<<1|1,l,r,x);
    pushup(u);
}
MA query(int u,int l,int r){
    if(tr[u].l>=l&&tr[u].r<=r){
        return tr[u].sum;
    }
    if(tr[u].lazy!=I)
        pushdown(u);
    int mid=tr[u].l+tr[u].r>>1;
    MA res;
    if(l<=mid)
        res=res+query(u<<1,l,r);
    if(r>mid)
        res=res+query(u<<1|1,l,r);
    return res;
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    int i;
    init();
    for(i=1;i<=n;i++)
        cin>>a[i];
    build(1,1,n);
    while(m--){
        int opt;
        cin>>opt;
        if(opt==1){
            int l,r,x;
            cin>>l>>r>>x;
            modify(1,l,r,qpow(Q,x));
        }
        else{
            int l,r;
            cin>>l>>r;
            cout<<(P*query(1,l,r)).a[0][0]<<endl;
        }
    }
    return 0;
}
View Code

 

posted @ 2020-10-03 21:40  朝暮不思  阅读(222)  评论(1编辑  收藏  举报