給定一個序列A1 A2 .. AN 和M個查詢ios
求Fi(Ri)函數
根據遞推式能夠構造一個矩陣:ui
繼續展開,最終矩陣就是這個樣子的了spa
所以每次查詢就是求矩陣的連乘code
普通的作法就是每查詢一次線性計算一次上式,時間複雜度O(n),因此總的時間複雜度爲O(m*n),顯然要跪。。。線段樹就很好的解決了這個問題,每一個結點保存的都是一個矩陣,這樣查詢的時候就只須要O(logn)的時間了!blog
#include <iostream> #include <string> #include <cstring> #include <stdio.h> using namespace std; #define maxn 100005 #define MOD 1000000007 #define lson l,m,s<<1 #define rson m+1,r,s<<1|1 typedef long long LL; struct Matrix { LL mat[2][2]; int r; void init(int n) { memset(mat,0,sizeof(mat)); r=n; } }; Matrix matrix_mul(Matrix a,Matrix b) { Matrix ans; ans.init(a.r); for(int i=0; i<a.r; i++) for(int j=0; j<a.r; j++) for(int k=0; k<a.r; k++) if(a.mat[i][k]&&b.mat[k][j]) ans.mat[i][j]=(ans.mat[i][j]+a.mat[i][k]*b.mat[k][j])%MOD; return ans; } LL a[maxn]; Matrix sum[maxn<<2]; void Pushup(int s) { sum[s]=matrix_mul(sum[s<<1|1],sum[s<<1]); } void build(int l,int r,int s) { sum[s].init(2); if(l==r) { sum[s].mat[0][0]=sum[s].mat[1][0]=1; sum[s].mat[0][1]=a[r]; return; } int m=(l+r)>>1; build(lson); build(rson); Pushup(s); } Matrix query(int ql,int qr,int l,int r,int s) { if(ql<=l&&r<=qr) return sum[s]; int m=(l+r)>>1; Matrix ret; ret.init(2); ret.mat[0][0]=ret.mat[1][1]=1; if(qr>m) ret=matrix_mul(ret,query(ql,qr,rson)); if(ql<=m) ret=matrix_mul(ret,query(ql,qr,lson)); return ret; } int main() { int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) scanf("%lld",&a[i]); build(1,n,1); while(m--) { int l,r; scanf("%d%d",&l,&r); if(l==r||(l+1)==r) { printf("%lld\n",a[r]); continue; } Matrix ans=query(l+2,r,1,n,1); //printf("%I64d %I64d\n",ans.mat[0][0],ans.mat[0][1]); // printf("%I64d %I64d\n",ans.mat[1][0],ans.mat[1][1]); printf("%lld\n",(ans.mat[0][0]*a[l+1]+ans.mat[0][1]*a[l])%MOD); } } return 0; }