zoukankan      html  css  js  c++  java
  • 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
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    linux中按行读取指定行
    linux常用配置文件
    linux虚拟机设置网络
    jenkins新建一个robot脚本的job
    jenkins中配置邮件发送
    jenkins中robot framework插件安装
    Jenkins subversion svn插件安装失败
    jenkins节点启动
    {"non_field_errors":["Unable to log in with provided credentials."]}% 无法使用提供的凭据登录
    路径模板
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13765610.html
Copyright © 2011-2022 走看看