首页 > 代码库 > Codeforces 719E [斐波那契区间操作][矩阵快速幂][线段树区间更新]
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 2using 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 [斐波那契区间操作][矩阵快速幂][线段树区间更新]
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。