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 }

时间: 2024-08-01 10:33:07

CF719E(线段树+矩阵快速幂)的相关文章

2017省夏令营Day7 【快速幂,筛法,矩阵快速幂,线段树】

题解:首先,我们可以得到一个规律:经过2次变换后,a和b的值都分别乘2了,所以只要用快速幂就能过啦,但是,要特判n为0的情况. 代码如下: 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define Mod 1000000007 5 using namespace std; 6 long long a,b,n,ans1,ans2; 7 long long power(long long x)

多校第九场:贪心+矩阵快速幂中间优化+线性递推&amp;线段树递推

HDU 4968 Improving the GPA 思路:贪心的搞吧!比赛的时候想了好久,然后才发现了点规律,然后乱搞1A. 因为贪心嘛!大的情况就是刚开始每个人的分数都是最大的最小值,即绩点4.0的最低分数85,然后最后一个数设为剩余的分数,然后如果小于60就从第一个分数补到这个分数来,然后最后一个分数还小于60,那就用第二个补--依次往下搞,那时我也不知道这样就搞出答案了,我还没证明这个对不对呢,哈哈. 小的情况:小的情况就是先假设每个人都是绩点最小的最大分数,即绩点2.0的最大分数69,

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这种形式时间几乎

【66测试20161115】【树】【DP_LIS】【SPFA】【同余最短路】【递推】【矩阵快速幂】

还有3天,今天考试又崩了.状态还没有调整过来... 第一题:小L的二叉树 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣.所以,小L当时卡在了二叉树. 在计算机科学中,二叉树是每个结点最多有两个子结点的有序树.通常子结点被称作“左孩子”和“右孩子”.二叉树被用作二叉搜索树和二叉堆.随后他又和他人讨论起了二叉搜索树.什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树.设key[p]表示结点p上的数值.对于其中的每个结点p,若其存在左孩子lch,则key

【模板】矩阵快速幂 洛谷P2233 [HNOI2002]公交车路线

P2233 [HNOI2002]公交车路线 题目背景 在长沙城新建的环城公路上一共有8个公交站,分别为A.B.C.D.E.F.G.H.公共汽车只能够在相邻的两个公交站之间运行,因此你从某一个公交站到另外一个公交站往往要换几次车,例如从公交站A到公交站D,你就至少需要换3次车. Tiger的方向感极其糟糕,我们知道从公交站A到公交E只需要换4次车就可以到达,可是tiger却总共换了n次车,注意tiger一旦到达公交站E,他不会愚蠢到再去换车.现在希望你计算一下tiger有多少种可能的乘车方案. 题

poj2778 ac自动机+矩阵快速幂

给m个子串,求长度为n的不包含子串的母串数,最直接的应该是暴搜,肯定tle,考虑用ac自动机 将子串建成字典树,通过next表来构造矩阵,然后用矩阵快速幂求长度为n的数量 邻接矩阵https://wenku.baidu.com/view/d7b9787f1711cc7931b716b0.html 对于a(i,j)^k  是指从i到j经过k个点的所有情况数 注意对于End数组,如果某个节点如果fail指针End数组为1,那么End[该节点]也是1 string要开全局变量,不然不能运行= = #i

CF821 E. Okabe and El Psy Kongroo 矩阵快速幂

LINK 题意:给出$n$条平行于x轴的线段,终点$k$坐标$(k <= 10^{18})$,现在可以在线段之间进行移动,但不能超出两条线段的y坐标所夹范围,问到达终点有几种方案. 思路:刚开始以为限制只是到达线段上就必须沿线段走,后来才发现是要求走y坐标所夹范围,那么就简单多了,很容易看出是个递推形DP,然而数据量有点大,k为10的18次,一般转移显然不可行.由于是个递推,而且y坐标最大也只有15,故使用矩阵优化递推复杂度即可. /** @Date : 2017-07-04 16:06:18

矩阵快速幂(转载)

super_boy原创文章,转载请注明出处http://www.cnblogs.com/yan-boy/archive/2012/11/29/2795294.html 矩阵的快速幂是用来高效地计算矩阵的高次方的.将朴素的o(n)的时间复杂度,降到log(n). 这里先对原理(主要运用了矩阵乘法的结合律)做下简单形象的介绍: 一般一个矩阵的n次方,我们会通过连乘n-1次来得到它的n次幂. 但做下简单的改进就能减少连乘的次数,方法如下: 把n个矩阵进行两两分组,比如:A*A*A*A*A*A  =>

【CF696D】Legen...(AC自动机)(矩阵快速幂)

题目描述 Barney was hanging out with Nora for a while and now he thinks he may have feelings for her. Barney wants to send her a cheesy text message and wants to make her as happy as possible. Initially, happiness level of Nora is 0 0 . Nora loves some p