Codeforces 719E [斐波那契区间操作][矩阵快速幂][线段树区间更新]
Posted 徐暾
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 719E [斐波那契区间操作][矩阵快速幂][线段树区间更新]相关的知识,希望对你有一定的参考价值。
/* 题意:给定一个长度为n的序列a。 两种操作: 1.给定区间l r 加上某个数x. 2.查询区间l r sigma(fib(ai)) fib代表斐波那契数列。 思路: 1.矩阵操作,由矩阵快速幂求一个fib数根据矩阵的乘法结合率,A*C+B*C=(A+B)*C; 这样可以通过线段树维护某个区间2*1矩阵的和。 2.时限卡的紧...用我的矩阵乘法板子TLE了。所以把板子里边的三重循环改成手工公式... 3.注意(a+b)%mod。这种,改成if(a+b>=mod)a+b-mod这种形式时间几乎减半了==...(因为查询和更新操作每次都要把两个矩阵加起来...所以这种优化在这题来说作用明显) 4.注意lazy标记不要记录要乘多矩阵多少次方...而是直接记录该矩阵...这是最重要的一个优化(个人认为).因为每次向下层更新都要求一次矩阵... */ #include<bits/stdc++.h> #define N 100020 #define MAXS 2 using namespace std; long long jilu[N]; long long jil[N]; long long MOD =1e9+7; struct Matrix { long long mx[MAXS][MAXS]; Matrix() { memset(mx,0,sizeof(mx)); } Matrix operator* (const Matrix& b) const { Matrix tmp; tmp.mx[0][0]=mx[0][0]*b.mx[0][0]+mx[0][1]*b.mx[1][0]; if(tmp.mx[0][0]>=MOD)tmp.mx[0][0]%=MOD; tmp.mx[0][1]=mx[0][0]*b.mx[0][1]+mx[0][1]*b.mx[1][1]; if(tmp.mx[0][1]>=MOD)tmp.mx[0][1]%=MOD; tmp.mx[1][0]=mx[1][0]*b.mx[0][0]+mx[1][1]*b.mx[1][0]; if(tmp.mx[1][0]>=MOD)tmp.mx[1][0]%=MOD; tmp.mx[1][1]=mx[1][0]*b.mx[0][1]+mx[1][1]*b.mx[1][1]; if(tmp.mx[1][1]>=MOD)tmp.mx[1][1]%=MOD; return tmp; } Matrix operator +(const Matrix &b)const{ Matrix tmp; for(int i=0;i<2;i++){ for(int j=0;j<2;j++){ tmp.mx[i][j]=(mx[i][j]+b.mx[i][j]); if(tmp.mx[i][j]>=MOD)tmp.mx[i][j]-=MOD; } } return tmp; } void initE() { memset(mx,0, sizeof(mx)); for (int i=0 ; i<2 ; i++) { mx[i][i]=1; } } Matrix mpow(long long k) { Matrix c,b; c=(*this); b.initE(); while(k) { if(k&1) { b=b*c; } c=c*c; k>>=1; } return b; } }; Matrix biao,ben; struct tr{ Matrix val,tt; long long aa; int s,e; }; tr tree[100050<<2]; void build(int s,int e,int k){ tr &tmp=tree[k]; tmp.s=s;tmp.e=e;tmp.aa=0; tmp.tt.initE(); if(s==e){ tmp.val.mx[0][0]=jilu[s]; tmp.val.mx[1][0]=jil[s]; return; } int mid=(s+e)>>1; build(s,mid,k<<1); build(mid+1,e,k<<1|1); tmp.val=tree[k<<1].val+tree[k<<1|1].val; } void add(int s,int e,int k,int num){ tr &tmp=tree[k]; if(s==tmp.s&&e==tmp.e){ Matrix ttt=biao.mpow(num); tmp.tt=ttt*tmp.tt; tmp.val=ttt*tmp.val; tmp.aa+=num; return; } if(tmp.aa){ tree[k<<1].aa+=tmp.aa; tree[k<<1].val=tmp.tt*tree[k<<1].val; tree[k<<1].tt=tmp.tt*tree[k<<1].tt; tree[k<<1|1].aa+=tmp.aa; tree[k<<1|1].val=tmp.tt*tree[k<<1|1].val; tree[k<<1|1].tt=tmp.tt*tree[k<<1|1].tt; tmp.tt.initE(); tmp.aa=0; } int mid=(tmp.s+tmp.e)>>1; if(e<=mid)add(s,e,k<<1,num); else if(s>mid)add(s,e,k<<1|1,num); else{ add(s,mid,k<<1,num); add(mid+1,e,k<<1|1,num); } tmp.val=tree[k<<1].val+tree[k<<1|1].val; } long long query(int s,int e,int k){ tr &tmp=tree[k]; if(tmp.s==s&&tmp.e==e){ return tmp.val.mx[0][0]; } if(tmp.aa){ tree[k<<1].aa+=tmp.aa; tree[k<<1].val=tmp.tt*tree[k<<1].val; tree[k<<1].tt=tmp.tt*tree[k<<1].tt; tree[k<<1|1].aa+=tmp.aa; tree[k<<1|1].val=tmp.tt*tree[k<<1|1].val; tree[k<<1|1].tt=tmp.tt*tree[k<<1|1].tt; tmp.tt.initE(); tmp.aa=0; } int mid=(tmp.s+tmp.e)>>1; if(e<=mid)return query(s,e,k<<1); else if(s>mid)return query(s,e,k<<1|1); else return (query(s,mid,k<<1)+query(mid+1,e,k<<1|1))%MOD; } int main() { int n,m; biao.mx[0][0]=biao.mx[0][1]=biao.mx[1][0]=1; ben.mx[1][0]=ben.mx[0][0]=1; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%lld",jilu+i); if(jilu[i]==1){ jil[i]=0; } else if(jilu[i]==2){ jilu[i]=1; jil[i]=1; } else{ Matrix rel=biao.mpow(jilu[i]-2)*ben; jilu[i]=rel.mx[0][0]; jil[i]=rel.mx[1][0]; } } build(1,n,1); for(int i=1;i<=m;i++){ int typ,l,r,x; scanf("%d",&typ); if(typ==1){ scanf("%d%d%d",&l,&r,&x); add(l,r,1,x); } else{ scanf("%d%d",&l,&r); printf("%lld\n",query(l,r,1)); } } }
以上是关于Codeforces 719E [斐波那契区间操作][矩阵快速幂][线段树区间更新]的主要内容,如果未能解决你的问题,请参考以下文章
[莫队算法 线段树 斐波那契 暴力] Codeforces 633H Fibonacci-ish II
Codeforces718 C. Sasha and Array(线段树维护矩阵,矩阵快速幂求斐波那契数列,矩阵乘法结合律)
codeforces316E3 Summer Homework(线段树,斐波那契数列)