首页 > 代码库 > CF719E(线段树+矩阵快速幂)
CF719E(线段树+矩阵快速幂)
题意:给你一个数列a,a[i]表示斐波那契数列的下标为a[i],求区间对应斐波那契数列数字的和,还要求能够维护对区间内所有下标加d的操作
分析:线段树
线段树的每个节点表示(f[i],f[i-1])这个数组
因为矩阵的可加性,所以可以进行lazy操作
我最开始的想法是每个节点lazy表示该区间下标加了多少,add表示该区间已经加的下标对应的矩阵乘积,这样更新lazy是O(1)的,算add是O(logn)的
但是这样每次pushdown的时候,add下传总要多个log,会TLE
更好的办法是lazy表示加的下标对应的矩阵乘积,这样虽然每次更新lazy是O(logn)的,但是pushdown的时候就是直接把(f[i],f[i-1])和lazy[2][2]乘起来了,是O(1)的
代码:
1 #include<bits/stdc++.h> 2 const int maxn=1e5; 3 const long long mod=1e9+7; 4 int ch[maxn*2+50][2]; 5 long long sum[maxn*2+50][2],add[maxn*2+50][2][2],a[maxn+50]; 6 int len=0,n,m; 7 void mer(long long a[2][2],long long b[2][2]) 8 { 9 long long s[2][2]; 10 memset(s,0,sizeof(s)); 11 for(int i=0;i<2;++i) 12 for(int j=0;j<2;++j) 13 for(int k=0;k<2;++k) 14 s[i][j]=(s[i][j]+a[i][k]*b[k][j]%mod)%mod; 15 for(int i=0;i<2;++i) 16 for(int j=0;j<2;++j) 17 a[i][j]=s[i][j]; 18 } 19 void fib(long long num[2][2],long long x) 20 { 21 long long a[2][2]={{1,1},{1,0}}; 22 num[0][0]=1,num[0][1]=0,num[1][0]=0,num[1][1]=1; 23 while(x) 24 { 25 if(x&1) mer(num,a); 26 mer(a,a); 27 x>>=1; 28 } 29 } 30 void cal(long long sum[2],long long s[2][2]) 31 { 32 long long x=(sum[0]*s[0][0]%mod+sum[1]*s[1][0]%mod)%mod; 33 long long y=(sum[0]*s[0][1]%mod+sum[1]*s[1][1]%mod)%mod; 34 sum[0]=x,sum[1]=y; 35 } 36 void pushdown(int k) 37 { 38 if(add[k][0][0]==1&&add[k][0][1]==0&&add[k][1][0]==0&&add[k][1][1]==1) return; 39 //printf("A"); 40 //cal(sum[k],add[k]); 41 int l=ch[k][0],r=ch[k][1]; 42 if(l) mer(add[l],add[k]),cal(sum[l],add[k]); 43 if(r) mer(add[r],add[k]),cal(sum[r],add[k]); 44 add[k][0][0]=1,add[k][0][1]=0,add[k][1][0]=0,add[k][1][1]=1; 45 } 46 void update(int k) 47 { 48 int l=ch[k][0],r=ch[k][1]; 49 //cal(sum[k],add[k]); 50 //pushdown(k); 51 for(int i=0;i<2;++i) sum[k][i]=(sum[l][i]+sum[r][i])%mod; 52 // if(k==2) printf("A : %d %d %lld %lld\n",l,r,sum[l][0],sum[r][0]); 53 } 54 int build(int l,int r) 55 { 56 if(l>r) return 0; 57 int mid=(l+r)>>1; 58 int k=++len; 59 add[k][0][0]=1,add[k][0][1]=0,add[k][1][0]=0,add[k][1][1]=1; 60 if(l==r) 61 { 62 sum[k][0]=1,sum[k][1]=0; 63 long long num[2][2]; 64 fib(num,a[l]-1); 65 cal(sum[k],num); 66 //printf("%d %d %d %d %d\n",l,r,k,ch[k][0],ch[k][1]); 67 return k; 68 } 69 ch[k][0]=build(l,mid); 70 ch[k][1]=build(mid+1,r); 71 update(k); 72 return k; 73 // printf("%d %d %d %d %d\n",l,r,k,ch[k][0],ch[k][1]); 74 } 75 void make(int k,int l,int r,int x,int y,long long num[2][2]) 76 { 77 if(l>r) return; 78 if(l>y||r<x) return; 79 if(x<=l&&y>=r) 80 { 81 mer(add[k],num); 82 cal(sum[k],num); 83 return; 84 } 85 int mid=(l+r)>>1; 86 pushdown(k); 87 if(l<=mid) make(ch[k][0],l,mid,x,y,num); 88 if(r>mid) make(ch[k][1],mid+1,r,x,y,num); 89 update(k); 90 } 91 long long query(int k,int l,int r,int x,int y) 92 { 93 if(l>r) return 0; 94 if(l>y||r<x) return 0; 95 if(x<=l&&y>=r) 96 { 97 return sum[k][0]; 98 } 99 int mid=(l+r)>>1; 100 pushdown(k); 101 return (query(ch[k][0],l,mid,x,y)+query(ch[k][1],mid+1,r,x,y))%mod; 102 } 103 int main() 104 { 105 106 scanf("%d %d",&n,&m); 107 for(int i=1;i<=n;++i) scanf("%lld",&a[i]); 108 build(1,n); 109 //for(int i=1;i<=len;++i) printf("%d %lld %lld\n",i,sum[i][0],sum[i][1]); 110 //or(int i=1;i<=len;++i) printf("%d %lld %lld %lld %lld\n",i,add[i][0][0],add[i][0][1],add[i][1][0],add[i][1][1]); 111 for(int i=1;i<=m;++i) 112 { 113 int t,l,r; 114 long long x; 115 scanf("%d %d %d",&t,&l,&r); 116 if(t==1) 117 { 118 scanf("%lld",&x); 119 long long num[2][2]; 120 fib(num,x); 121 make(1,1,n,l,r,num); 122 } 123 else printf("%lld\n",query(1,1,n,l,r)); 124 } 125 return 0; 126 }
CF719E(线段树+矩阵快速幂)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。