聪哥推荐的题目

区间修改和区间查询,但是此题新颖之处就在于他的区间修改不是个定值,而是从L 到 R 分别加 F1、F2、。。。Fr-l+1 (F为斐波那契数列)

想了一下之后,觉得用fib的前缀和来解决,每次做懒惰标记记录下当前区间是从哪个L开始加起的,敲了一半之后发现有问题,就跟上次遇到的懒惰标记问题一样,这是个覆盖性的懒惰标记,每次向下传递后,都要先清除孩子的,清除孩子的也有可能要清除son's son,所以要一直pushdown下去,否则就会错,但这样就会超时。

能不能有个累加型的标记让我不用pushdown呢,网上都用的什么二次剩余定理,实在不会

后来发现一个博客的做法相当精妙,利用了斐波那契的特性

我们知道 fib总是由两个两个往后推得  则

若当前 数列前两项 为 a 、b,则之后的必为  a+b a+2b 2a+3b 3a+5b

推完发现 只要知道前两项,后面的任意一项都可以马上出来,因为其系数也满足fib数列

令 K=1,0,1,1,2.。。Ki=Ki-1+Ki-2,。

再令 F=0,1,1,2,3.。。为普通fib数列

则知道 前两项为 a,b,可推算出任意一项 n=Kn*a+Gn*b;

同理,我们可以推算出来,知道前两项后,前n项的总和为

Fn*a+Sn*b(S为fib的前缀和)。

这样的话,我只要每次懒惰标记当前区间的前两项,向下传递就会马上得到区间的加值,并且传递给左右孩子的时候,能根据右孩子的区间不同,马上把前两项变为适合右孩子的那两项。。。最重要的是,这个前两项支持累加,也就是累加型懒惰标记,不用彻底向下传递,这真的是极好的

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #define LL __int64
  5. #define lson rt<<1,l,mid
  6. #define rson rt<<1|1,mid+1,r
  7. const LL M=;
  8. const int N=+;
  9. LL F[N],K[N],G[N],A[N];
  10. int n,m;
  11. LL d[N<<],f[N<<],f1[N<<],f2[N<<];
  12. void init()
  13. {
  14. F[]=G[]=;
  15. K[]=;
  16. F[]=;
  17. G[]=;
  18. K[]=;
  19. for (int i=;i<=n+;i++){
  20. F[i]=F[i-]+F[i-];
  21. K[i]=K[i-]+K[i-];
  22. G[i]=G[i-]+F[i-];
  23. if (F[i]>=M) F[i]%=M;
  24. if (K[i]>=M) K[i]%=M;
  25. if (G[i]>=M) G[i]%=M;
  26. }
  27. for (int i=;i<=n;i++) scanf("%d",&A[i]);
  28. }
  29. void up(int rt)
  30. {
  31. d[rt]=d[rt<<]+d[rt<<|];
  32. if (d[rt]>=M) d[rt]%=M;
  33. }
  34. void build(int rt,int l,int r)
  35. {
  36. f[rt]=;
  37. if (l>=r){
  38. d[rt]=A[l]%M;
  39. return;
  40. }
  41. int mid=(l+r)>>;
  42. build(lson);
  43. build(rson);
  44. up(rt);
  45. }
  46. void fix(LL v1,LL v2,int L,int R,int rt,int l,int r);
  47. void pushdown(int rt,int l,int r)
  48. {
  49. if (l>=r) return;
  50. if (!f[rt]) return;
  51. int mid=(l+r)>>;
  52. fix(f1[rt],f2[rt],l,mid,lson);
  53.  
  54. LL t1=K[mid-l+]*f1[rt]%M+K[mid-l+]*f2[rt]%M;
  55. LL t2=K[mid-l+]*f1[rt]%M+K[mid-l+]*f2[rt]%M;
  56. if (t1>=M) t1%=M;
  57. if (t2>=M) t2%=M;
  58. fix(t1,t2,mid+,r,rson);
  59. f[rt]=;
  60.  
  61. }
  62. void fix(LL v1,LL v2,int L,int R,int rt,int l,int r)
  63. {
  64. if (L==l && r==R){ //采用这种锁定区间的方法是因为下面有个地方要用L计算,我之前的那种写法会出错
  65. d[rt]+=(v1*F[R-L+]%M+G[R-L+]*v2%M)%M;
  66. if (d[rt]>=M) d[rt]%=M;
  67. if (!f[rt]){
  68. f1[rt]=v1%M;
  69. f2[rt]=v2%M;
  70. f[rt]=;
  71. }
  72. else{
  73. f1[rt]+=v1%M;
  74. f2[rt]+=v2%M;
  75. if (f1[rt]>=M) f1[rt]%=M;
  76. if (f2[rt]>=M) f2[rt]%=M;
  77. }
  78. return;
  79. }
  80. int mid=(l+r)>>;
  81. pushdown(rt,l,r);
  82. if (R<=mid) fix(v1,v2,L,R,lson);
  83. else if (L>mid) fix(v1,v2,L,R,rson);
  84. else {
  85. fix(v1,v2,L,mid,lson);
  86. LL t1=K[mid-L+]*v1%M+K[mid-L+]*v2%M;//这里L要进行计算,每个孩子对应唯一L,所以为什么我要采用这种锁定区间的方式,就是因为这里。以前以为两种锁定区间的方法差不多,现在找到区别了,如果只是简单为了锁定区间,两种都可以用,但是当区间要作为计算条件的时候,要采取这种方法避免错误
  87. LL t2=K[mid-L+]*v1%M+K[mid-L+]*v2%M;
  88. if (t1>=M) t1%=M;
  89. if (t2>=M) t2%=M;
  90. fix(t1,t2,mid+,R,rson);
  91. }
  92. up(rt);
  93. }
  94. LL query(int L,int R,int rt,int l,int r)
  95. {
  96. if (L<=l && r<=R){
  97. return d[rt]%M;
  98. }
  99. pushdown(rt,l,r);
  100. int mid=(l+r)>>;
  101. LL ret1=,ret2=;
  102. if (L<=mid) ret1=query(L,R,lson);
  103. if (R>mid) ret2=query(L,R,rson);
  104. return (ret1+ret2)%M;
  105. }
  106. int main()
  107. {
  108. int op,a,b;
  109. while (scanf("%d%d",&n,&m)!=EOF)
  110. {
  111. init();
  112. build(,,n);
  113. while (m--)
  114. {
  115. scanf("%d%d%d",&op,&a,&b);
  116. if (op==){
  117. fix(,,a,b,,,n);
  118. }
  119. else{
  120. LL ans=query(a,b,,,n);
  121. printf("%I64d\n",ans);
  122. }
  123. }
  124. }
  125. return ;
  126. }

Codeforces 446C 线段树 递推Fibonacci公式的更多相关文章

  1. Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论

    Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论 题意 给你一段数,然后小明去猜某一区间内的gcd,这里不一定是准确值,如果在这个区间内改变 ...

  2. codeforces 447E or 446C 线段树 + fib性质或二次剩余性质

    CF446C题意: 给你一个数列\(a_i\),有两种操作:区间求和:\(\sum_{i=l}^{r}(a[i]+=fib[i-l+1])\).\(fib\)是斐波那契数列. 思路 (一) codef ...

  3. Codeforces 719E (线段树教做人系列) 线段树维护矩阵

    题面简洁明了,一看就懂 做了这个题之后,才知道怎么用线段树维护递推式.递推式的递推过程可以看作两个矩阵相乘,假设矩阵A是初始值矩阵,矩阵B是变换矩阵,求第n项相当于把矩阵B乘了n - 1次. 那么我们 ...

  4. [BZOJ1089][SCOI2003]严格n元树(递推+高精度)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1089 分析: 第一感觉可以用一个通式求出来,但是考虑一下很麻烦,不好搞的.很容易发现最 ...

  5. Codeforces 316E3 线段树 + 斐波那切数列 (看题解)

    最关键的一点就是 f[ 0 ] * a[ 0 ] + f[ 1 ] * a[ 1 ] + ... + f[ n - 1] * a[ n  - 1] f[ 1 ] * a[ 0 ] + f[ 2 ] * ...

  6. Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem E (Codeforces 831E) - 线段树 - 树状数组

    Vasily has a deck of cards consisting of n cards. There is an integer on each of the cards, this int ...

  7. Please, another Queries on Array? CodeForces - 1114F (线段树,欧拉函数)

    这题刚开始看成求区间$\phi$和了........先说一下区间和的做法吧...... 就是说将题目的操作2改为求$(\sum\limits_{i=l}^{r}\phi(a[i]))\%P$ 首先要知 ...

  8. bzoj 1089 SCOI2003严格n元树 递推

    挺好想的,就是一直没调过,我也不知道哪儿的错,对拍也拍了,因为数据范围小,都快手动对拍了也不知道 哪儿错了.... 我们定义w[i]代表深度<=i的严格n元树的个数 那么最后w[d]-w[d-1 ...

  9. Codeforces 938G 线段树分治 线性基 可撤销并查集

    Codeforces 938G Shortest Path Queries 一张连通图,三种操作 1.给x和y之间加上边权为d的边,保证不会产生重边 2.删除x和y之间的边,保证此边之前存在 3.询问 ...

随机推荐

  1. 最简单的mybatis增删改查样例

    最简单的mybatis增删改查样例 Book.java package com.bookstore.app; import java.io.Serializable; public class Boo ...

  2. Xilinx COE文件格式小记

    官方的参考文档是:https://www.xilinx.com/support/documentation/sw_manuals/xilinx11/cgn_r_coe_file_syntax.htm ...

  3. MySQL存储过程例子

    -- 索引 INDEXCREATE INDEX idx_sname ON student( sname(4)); ALTER TABLE teacher add index idx_tname(tna ...

  4. win10安装mysql过程&&链接过程&&备份和导入数据&&grant命令

    win10安装mysql过程&&链接过程&&备份和导入数据&&grant命令   一 .安装 一开始在mysql官网(https://www.mysql ...

  5. flask-Bootstrap Jinja2 原生 模板 和 jumpserver 模板

    #模板 {% block doc -%} <!DOCTYPE html> <html{% block html_attribs %}{% endblock html_attribs ...

  6. 第1节 HUE:14、15、16、hue与hdfs、yarn集群、hive、impala、mysql的整合

    3.hue与其他框架的集成 3.1.hue与hadoop的HDFS以及yarn集成 第一步:更改所有hadoop节点的core-site.xml配置 记得更改完core-site.xml之后一定要重启 ...

  7. 最简单-转换MBR为GPT

    Windows Server 2016可能没有这个 mbr2gpt 这个软件,可以从Windows 10 的C:\Windows\System32 目录下面复制到 Windows Server 201 ...

  8. Java中遍历 Session 和 Request

    转: session的遍历: java.util.Enumeration e = request.getSession().getAttributeNames(); while( e.hasMoreE ...

  9. 微信小程序-发送模板消息

    1 添加一个小程序的消息模板,获取到模板id,存储到数据库中,方便以后修改调用 2. https://developers.weixin.qq.com/miniprogram/dev/api-back ...

  10. LINUX——LVM逻辑卷管理

    LVM: logical volumes manager LVM逻辑卷部署 物理卷—>卷组—>逻辑卷 第一步:关机添加磁盘:两个磁盘可以构成一个磁盘组. 第二步:查看磁盘 # ls /de ...