题目大意

给定一个n个数的数列,m个操作,有三种操作:

\(1\ x\ v\) 将\(a_x\)的值修改成v



$2\ l\ r\ $ 求 \(\sum_{i=l}^r x_i*f_{i-l}\) 其中对于\(f\)数组 \(f_0=1\ ,f_1=1\ ,f_i=f_{i-1}+f_{i-2}\) (就是斐波那契数列)



$3\ l\ r\ x\ $ 让\(a_i+x,i\in[l,r]\)

其中$n\le 100000,m\le 100000$

一看这个题QwQ,就知道是线段树题

QwQ那么怎么维护节点信息和合并区间呢

来举个栗子试一下

对于系数分别为\(1\ 1,1\ 2\)来说

将二者相加变为\(2\ 3\)也就是以第三个元素开头的系数序列了~

由于fib序列相加还是fib序列

哇,那这么说,这个题目所给的求和的操作,也是可以通过已知矩阵乘转移矩阵快速得到目标矩阵

那么!就可以通过这个东西来转移了!

\[\begin{bmatrix}
0 & 1 \\
1& 1 \\
\end{bmatrix}
\]

所以!对于左右区间来说,合并的时候,只需要把右区间乘上左区间的长度次方(就相当于把右边这个区间的变为$f_{mid-l+1}$项开头)

同时,我们发现要进行矩阵转移,必须记录当前这个区间的元素从\(f_0\)开始和\(f_1\)开始的两个值,才能够进行矩阵计算

QwQ因为我不会矩阵乘法呀!

所以我是选择手动展开了矩阵的n次方

最后假设是求矩阵的n次方的话

那么最终的矩阵应为

\[\begin{bmatrix}
{fib}_{n-2} & {fib}_{n-1} \\
{fib}_{n-1}& {fib}_{n} \\
\end{bmatrix}
\]

~只需要预处理一下fib序列和fib序列的前缀和就行了

  1. void up(int root)
  2. {
  3. ll len = f[2*root].len;
  4. f[root].len=(f[2*root].len+f[2*root+1].len)%mod;
  5. f[root].fir=(f[2*root].fir+f[2*root+1].fir*get(len-2)+f[2*root+1].sec*fib[len-1])%mod;
  6. f[root].sec=(f[2*root].sec+f[2*root+1].fir*fib[len-1]+f[2*root+1].sec*fib[len])%mod;
  7. }

接着,我们考虑,对3操作

如果让一个区间加x,就是让这个区间加x*fib前缀和的区间长度-1项(因为\(f_0=1\))(求答案的是从\(f_0\)开始乘)

emmmm所以也是可以直接做了咯(记得从1开始乘的那个信息需要-add[root])

  1. void pushdown(int root,int l,int r)
  2. {
  3. if (add[root])
  4. {
  5. add[2*root]=(add[2*root]+add[root])%mod;
  6. add[2*root+1]=(add[2*root+1]+add[root])%mod;
  7. f[2*root].fir=(f[2*root].fir+add[root]*sum[f[2*root].len-1])%mod;
  8. f[2*root].sec=(f[2*root].sec+add[root]*sum[f[2*root].len]-add[root])%mod;
  9. f[2*root+1].fir=(f[2*root+1].fir+add[root]*sum[f[2*root+1].len-1])%mod;
  10. f[2*root+1].sec=(f[2*root+1].sec+add[root]*sum[f[2*root+1].len]-add[root])%mod; //之所以-1是因为要减掉fib[0]
  11. add[root]=0;
  12. }
  13. }

update和change和build都差不多~

需要注意的是!!!!!!!!!

query的时候,不能直接\(return\ f[root].fir\)

因为如果让区间为\([l,r]\),就需要将这一段嫁接到\([x,l-1]\)的后面,对,所以也需要想之前合并的时候那样乘一个fib

  1. if (x<=l && r<=y)
  2. {
  3. int len = l-1-x+1;
  4. if (len==0) return f[root].fir;
  5. return f[root].fir*get(len-2)+f[root].sec*get(len-1);
  6. }

其他的都差不多了啦

直接上代码!

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<cstdlib>
  7. #include<queue>
  8. #include<map>
  9. #include<vector>
  10. #define ll long long
  11. using namespace std;
  12. inline ll read()
  13. {
  14. ll x=0,f=1;char ch=getchar();
  15. while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  16. while (isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
  17. return x*f;
  18. }
  19. const int maxn = 2e5+1e2;
  20. const int mod = 1000000000;
  21. struct Node
  22. {
  23. ll fir,sec,len;
  24. };
  25. Node f[4*maxn];
  26. ll add[4*maxn];
  27. ll a[maxn];
  28. ll fib[maxn],sum[maxn];
  29. int n,m;
  30. void init()
  31. {
  32. fib[0]=1,fib[1]=1;
  33. for (int i=2;i<=n;i++) fib[i]=(fib[i-1]+fib[i-2])%mod;
  34. sum[0]=1;
  35. for (int i=1;i<=n;i++) sum[i]=(sum[i-1]+fib[i])%mod;
  36. }
  37. ll get(int x)
  38. {
  39. if (x<0) return 0;
  40. else return fib[x];
  41. }
  42. void up(int root)
  43. {
  44. ll len = f[2*root].len;
  45. f[root].len=(f[2*root].len+f[2*root+1].len)%mod;
  46. f[root].fir=(f[2*root].fir+f[2*root+1].fir*get(len-2)+f[2*root+1].sec*fib[len-1])%mod;
  47. f[root].sec=(f[2*root].sec+f[2*root+1].fir*fib[len-1]+f[2*root+1].sec*fib[len])%mod;
  48. }
  49. void pushdown(int root,int l,int r)
  50. {
  51. if (add[root])
  52. {
  53. add[2*root]=(add[2*root]+add[root])%mod;
  54. add[2*root+1]=(add[2*root+1]+add[root])%mod;
  55. f[2*root].fir=(f[2*root].fir+add[root]*sum[f[2*root].len-1])%mod;
  56. f[2*root].sec=(f[2*root].sec+add[root]*sum[f[2*root].len]-add[root])%mod;
  57. f[2*root+1].fir=(f[2*root+1].fir+add[root]*sum[f[2*root+1].len-1])%mod;
  58. f[2*root+1].sec=(f[2*root+1].sec+add[root]*sum[f[2*root+1].len]-add[root])%mod; //之所以-1是因为要减掉fib[0]
  59. add[root]=0;
  60. }
  61. }
  62. void build(int root,int l,int r)
  63. {
  64. if (l==r)
  65. {
  66. f[root].sec=f[root].fir=a[l]%mod;
  67. f[root].len=1;
  68. return;
  69. }
  70. int mid = (l+r) >> 1;
  71. build(2*root,l,mid);
  72. build(2*root+1,mid+1,r);
  73. up(root);
  74. }
  75. void update(int root,int l,int r,int x,int y,int p)
  76. {
  77. if (x<=l && r<=y)
  78. {
  79. add[root]=(add[root]+p)%mod;
  80. f[root].fir=(f[root].fir+sum[r-l]*p)%mod;
  81. f[root].sec=(f[root].sec+sum[r-l+1]*p-p)%mod;
  82. return;
  83. }
  84. pushdown(root,l,r);
  85. int mid = (l+r) >> 1;
  86. if (x<=mid) update(2*root,l,mid,x,y,p);
  87. if (y>mid) update(2*root+1,mid+1,r,x,y,p);
  88. up(root);
  89. }
  90. void change(int root,int l,int r,int x,int p)
  91. {
  92. if (l==r)
  93. {
  94. f[root].fir=f[root].sec=p%mod;
  95. add[root]=0;
  96. f[root].len=1;
  97. return;
  98. }
  99. pushdown(root,l,r);
  100. int mid = (l+r) >> 1;
  101. if (x<=mid) change(2*root,l,mid,x,p);
  102. if (x>mid) change(2*root+1,mid+1,r,x,p);
  103. up(root);
  104. }
  105. ll query(int root,int l,int r,int x,int y)
  106. {
  107. if (x<=l && r<=y)
  108. {
  109. int len = l-1-x+1;
  110. if (len==0) return f[root].fir;
  111. return f[root].fir*get(len-2)+f[root].sec*get(len-1);
  112. }
  113. int mid = (l+r) >> 1;
  114. pushdown(root,l,r);
  115. ll ans=0;
  116. if (x<=mid) ans=(ans+query(2*root,l,mid,x,y))%mod;
  117. if (y>mid) ans=(ans+query(2*root+1,mid+1,r,x,y))%mod;
  118. return ans%mod;
  119. }
  120. int main()
  121. {
  122. scanf("%d%d",&n,&m);
  123. init();
  124. for (int i=1;i<=n;i++) a[i]=read();
  125. build(1,1,n);
  126. //cout<<query(1,1,n,1,4)<<endl;
  127. for (int i=1;i<=m;i++)
  128. {
  129. int opt;
  130. opt=read();
  131. if (opt==1)
  132. {
  133. int x=read();
  134. ll y=read();
  135. change(1,1,n,x,y);
  136. }
  137. if (opt==2)
  138. {
  139. int x=read(),y=read();
  140. //cout<<x<<" "<<y<<endl;
  141. printf("%lld\n",query(1,1,n,x,y));
  142. //cout<<query(1,1,n,1,4)<<endl;
  143. }
  144. if (opt==3)
  145. {
  146. int x=read(),y=read();
  147. ll z=read();
  148. update(1,1,n,x,y,z);
  149. }
  150. }
  151. return 0;
  152. }

codeforces316E3 Summer Homework(线段树,斐波那契数列)的更多相关文章

  1. [Codeforces 316E3]Summer Homework(线段树+斐波那契数列)

    [Codeforces 316E3]Summer Homework(线段树+斐波那契数列) 顺便安利一下这个博客,给了我很大启发(https://gaisaiyuno.github.io/) 题面 有 ...

  2. Codeforces 446-C DZY Loves Fibonacci Numbers 同余 线段树 斐波那契数列

    C. DZY Loves Fibonacci Numbers time limit per test 4 seconds memory limit per test 256 megabytes inp ...

  3. 【CF446C】DZY Loves Fibonacci Numbers (线段树 + 斐波那契数列)

    Description ​ 看题戳我 给你一个序列,要求支持区间加斐波那契数列和区间求和.\(~n \leq 3 \times 10 ^ 5, ~fib_1 = fib_2 = 1~\). Solut ...

  4. [莫队算法 线段树 斐波那契 暴力] Codeforces 633H Fibonacci-ish II

    题目大意:给出一个长度为n的数列a. 对于一个询问lj和rj.将a[lj]到a[rj]从小到大排序后并去重.设得到的新数列为b,长度为k,求F1*b1+F2*b2+F3*b3+...+Fk*bk.当中 ...

  5. hdu 4983 线段树+斐波那契数

    http://acm.hdu.edu.cn/showproblem.php?pid=4893 三种操作: 1 k d, 修改k的为值增加d 2 l r, 查询l到r的区间和 3 l r, 从l到r区间 ...

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

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

  7. Codeforces 446C - DZY Loves Fibonacci Numbers(斐波那契数列+线段树)

    Codeforces 题目传送门 & 洛谷题目传送门 你可能会疑惑我为什么要写 *2400 的题的题解 首先一个很明显的想法是,看到斐波那契数列和 \(10^9+9\) 就想到通项公式,\(F ...

  8. HDU4099(斐波那契数列与字典树)

    题目:Revenge of Fibonacci 题意:给出斐波那契数列的前k位,k不超过40,找出最小的正整数n,满足F(n)的前k位与给定数的前k位相同,斐波那契数列的项数不超过100000. 解析 ...

  9. coderfoces446c (斐波那契数列)

    题目描述: 区间增值,但是每一项增加的值为Fi - l + 1,F[i]为斐波那契数列,求区间和? 考虑线段树,刚开始想用斐波那契数列的前n项和,可是推不出来,考虑到每个区间的增值序列都是一段斐波那契 ...

随机推荐

  1. golang GC 垃圾回收机制

    垃圾回收(Garbage Collection,简称GC)是编程语言中提供的自动的内存管理机制,自动释放不需要的对象,让出存储器资源,无需程序员手动执行. Golang中的垃圾回收主要应用三色标记法, ...

  2. 面试官:Redis的事务满足原子性吗?

    原创:码农参上(微信公众号ID:CODER_SANJYOU),欢迎分享,转载请保留出处. 谈起数据库的事务来,估计很多同学的第一反应都是ACID,而排在ACID中首位的A原子性,要求一个事务中的所有操 ...

  3. 使用Mosquitto实现MQTT客服端C语言

      上一篇文章已经将mosquitto移植到了arm平台上,现在将使用mosquitto完成mqtt客服端的demo,了解过mqtt协议的小伙伴都知道,mqtt主要分为代理服务器.发布者.订阅者三部分 ...

  4. 20210714 noip15

    考前 mtr 中午拿着笔记本改题(Orz),一点多发现 13.50 有比赛(截止 12 点都没放出来),赶紧睡.13.40 到了学校,巨瞌睡,洗了把脸到机房发现推迟到 14.30 了,wcnm 趴在桌 ...

  5. vue 路由视图,router-view嵌套跳转

    实现功能:制作一个登录页面,跳转到首页,首页包含菜单栏.顶部导航栏.主体,标准的后台网页格式.菜单栏点击不同菜单控制主体展示不同的组件(不同的页面). 配置router-view嵌套跳转需要准备两个主 ...

  6. Toast控件

    ------------恢复内容开始------------ 四种常见的App弹窗设计:Toast.Dialog.Actionbar 和 Snackbar 弹窗又称为对话框,是App与用户进行交互的常 ...

  7. 【曹工杂谈】Maven IOC容器的下半场:Google Guice

    Maven容器的下半场:Guice 前言 在前面的文章里,Maven底层容器Plexus Container的前世今生,一代芳华终落幕,我们提到,在Plexus Container退任后,取而代之的底 ...

  8. 使用AOP+自定义注解完成spring boot的接口权限校验

    记使用AOP+自定义注解完成接口的权限校验,代码如下: pom文件添加所需依赖: 1 <dependency> 2 <groupId>org.aspectj</group ...

  9. 在vue-cli项目中定义全局 filter、method 方法

    1.创建 filters.js(methods.js) 文件: 2.filters.js(methos.js) 中定义全局过滤方法: 1 export default { 2 /** 时间戳转换 */ ...

  10. Java集合:HashMap

    Hashmap是一个存储key-value的映射表. 优点: 索引数据快,查找一个数据对的时间复杂度是O(1) 增加.删除一个数据的时间复杂度是O(1) key不能重复,可以存储一个null值 存储: ...