線段樹維護矩陣【CF718C】 Sasha and Array
阿新 • • 發佈:2018-11-04
Description
有一個長為\(n\)的數列\(a_{1},a_{2}...a_{n}\),你需要對這個數列維護如下兩種操作:
- \(1\space l \space r\space x\) 表示將數列中的\(a_{l},a_{l+1}...a_{r-1},a_{r}\)加上\(x\)
- \(2\space l\space r\) 表示要你求出\(\sum_{i=l}^{r}fib(a_{i})\)對\(10^9+7\)取模後的結果
fib(x)fib(x)表示的是斐波那契的第\(x\)項,\(fib(1)=1,fib(2)=1,fib(i)=fib(i-1)+fib(i-2)(i>2)\)
線段樹維護矩陣。
emmm,嚇人。
看著題解碼
有些懵逼這種矩乘寫法。
為啥最普通的矩陣乘法不行???
調了半天發現快速冪裡面的\(for\)後面加了個分號??
區間修改操作即為原矩陣乘上轉移矩陣的\(x\)次方。
話說和我推的式子貌似又不是很一樣???QwQ?
程式碼
#include<iostream> #include<cstdio> #include<algorithm> #define int long long #define R register using namespace std; const int mod=1e9+7; const int gz=100001; inline void in(R int &x) { int f=1;x=0;char s=getchar(); while(!isdigit(s)){if(s=='-')f=-1;s=getchar();} while(isdigit(s)){x=x*10+s-'0';s=getchar();} x*=f; } int n,m,val[gz]; struct Matrix { int m[4][4]; inline void clear() { for(R int i=0;i<4;i++) for(R int j=0;j<4;j++) m[i][j]=0; } inline void pre() { for(R int i=0;i<4;i++)m[i][i]=1; } inline bool emp() { return (m[1][1]==1 and m[1][2]==0 and m[2][1]==0 and m[2][2]==1); } Matrix operator *(const Matrix &a)const { Matrix tmp;tmp.clear(); for(R int i=1;i<=2;i++) for(R int k=1;k<=2;k++) for(R int j=1;j<=2;j++) tmp.m[i][j]=(tmp.m[i][j]+m[i][k]*a.m[k][j])%mod; return tmp; } friend Matrix operator +(Matrix a,Matrix b) { Matrix tmp;tmp.clear(); for(R int i=1;i<=2;i++) for(R int j=1;j<=2;j++) tmp.m[i][j]=(a.m[i][j]+b.m[i][j])%mod; return tmp; } }; Matrix fir,fb; Matrix tr[gz<<2],tg[gz<<2]; #define ls o<<1 #define rs o<<1|1 inline void up(R int o) { tr[o]=tr[ls]+tr[rs]; } inline Matrix ksm(R Matrix a,R int y) { Matrix res;res.clear();res.pre(); for(;y;y>>=1,a=a*a) if(y&1)res=res*a; return res; } void build(R int o,R int l,R int r) { tr[o].clear();tg[o].clear();tg[o].pre(); if(l==r) { tr[o]=fir*ksm(fb,val[l]-1); return ; } R int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); up(o); } inline void down(R int o) { if(tg[o].emp())return; tr[ls]=tr[ls]*tg[o]; tr[rs]=tr[rs]*tg[o]; tg[ls]=tg[ls]*tg[o]; tg[rs]=tg[rs]*tg[o]; tg[o].clear(); tg[o].pre(); } void change(R int o,R int l,R int r,R int x,R int y,R Matrix k) { if(x<=l and y>=r) { tr[o]=tr[o]*k; tg[o]=tg[o]*k; return; } down(o); R int mid=(l+r)>>1; if(x<=mid) change(ls,l,mid,x,y,k); if(y>mid)change(rs,mid+1,r,x,y,k); up(o); } inline Matrix query(R int o,R int l,R int r ,R int x,R int y) { if(x<=l and y>=r)return tr[o]; down(o); Matrix res;res.clear(); R int mid=(l+r)>>1; if(x<=mid) res=res+query(ls,l,mid,x,y); if(y>mid) res=res+query(rs,mid+1,r,x,y); return res; } signed main() { fb.clear(),fir.clear(); fir.m[1][1]=fir.m[1][2]=1;fir.m[2][1]=fir.m[2][2]=0; fb.m[1][1]=fb.m[1][2]=fb.m[2][1]=1;fb.m[2][2]=0;//轉移矩陣 in(n),in(m); for(R int i=1;i<=n;i++)in(val[i]); build(1,1,n); for(R int opt,l,r,x;m;m--) { in(opt); switch(opt) { case 1:in(l),in(r),in(x);change(1,1,n,l,r,ksm(fb,x));break; case 2:in(l),in(r),printf("%lld\n",query(1,1,n,l,r).m[1][2]%mod);break; } } }