码迷,mamicode.com
首页 > 其他好文 > 详细

CF719E(线段树+矩阵快速幂)

时间:2016-12-17 02:31:46      阅读:310      评论:0      收藏:0      [点我收藏+]

标签:.com   [1]   数列   scanf   indicator   区间   view   分享   bsp   

题意:给你一个数列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 }
View Code

 

CF719E(线段树+矩阵快速幂)

标签:.com   [1]   数列   scanf   indicator   区间   view   分享   bsp   

原文地址:http://www.cnblogs.com/wmrv587/p/6188801.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!