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

顺便安利一下这个博客,给了我很大启发(https://gaisaiyuno.github.io/)

题面

有一个数列\(f_i\)满足\(f_0=f_1=1,f_i=f_{i-1}+f_{i-2}(i>2)\)(就是斐波那契数列)

给定一个n个数的数列a,m个操作,有3种操作

1.将\(a_x\)的值修改成v (单点修改)

2.对于\(i \in [l,r],a_i+=v\) (区间修改)

3.求\(\sum_{i=l}^r x_if_{i-l}\)

分析

显然是用线段树,考虑如何合并区间

定义\(s_0=f_0a_0+f_1a_1+...+f_na_n\),\(s_1=f_1a_0+f_2a_1+...+f_{n+1}a_n\)

即$$s_i=\sum_{j=0}^n f_{j+i}a_j$$

那么$$s_{i-2}+s_{i-1}= \sum_{j=0}^n f_{i-2+j}a_j+\sum_{j=0}^n f_{i-1+j}a_j= \sum_{j=0}^n (f_{i-2+j}+f_{i-1+j}) a_j$$

\(\because i-2+j+1=i-1+j,\ \therefore f_{i-2+j}+f_{i-1+j}=f_{i+j}\)

\(\therefore s_{i-2}+s_{i-1}=\sum_{j=0}^n (f_{i-2+j}+f_{i-1+j}) a_j=\sum_{j=0}^n f_{i+j} a_j=s_i\)

于是我们得到了非常重要的一个性质$$ s_i=s_{i-1}+s_{i-2} $$

直接在线段树上记录s肯定是不行的,现在我们想办法用\(s_0\)和\(s_1\)推出任意\(s_n\)

不妨设\(s_0=A,s_1=B\),发现\(s_2=s_0+s_1=1\times A+1\times B=f_0A+f_1B\)

$ \because f_0=f_1,f_2=f_1+f_0=f_1+f_1$

\(\therefore s_3=s_1+s_2=f_1B+f_0A+f_1B=f_1A+f_2B\)

\(s_4=s_2+s_3=(f_0+f_1)A+(f_1+f_2)B=f_2A+f_3B\)

\(s_5=s_3+s_4=(f_1+f_2)A+(f_2+f_3)B=f_3A+f_4B\)

\(\dots\)

根据数学归纳法,$$s_i=f_{i-2}s_0+f_{i-1}s_1$$

那么,如何把这几个结论运用到线段树上呢?

(1)pushup:

我们考虑合并线段树节点x的两个子节点lx,rx,得到x的s0,s1值,设子节点的区间为\([l,md],[md+1,r]\)

\[s_0(x)=\sum_{i=0}^{r-l} f_is_i=\sum_{i=0}^{md-l} f_is_i+\sum_{i=md+1-l}^{r-l}f_is_i
\]

容易看出\(\sum_{i=0}^{md} f_is_i=s_0(lx),\sum_{i=md+1-l}^{r-l}f_is_i=\sum_{j=0}^{r-md-1} f_{j+(md-l+1)}a_j=s_{md-l+1}(rx)=s_{len(lx)}(rx)\),其中len(k)表示k节点对应的区间长度,其实就是相当于把右区间的s值偏移了左区间长度那么多

所以有\(s_0(x)=s_0(lx)+s_{len(lx)}(rx)\),同理有\(s_1(x)=s_1(lx)+s_{len(lx)+1}(rx)\)

(2)push_down

考虑区间加法对答案的贡献,假设加上的数为\(\Delta\)

\(s_0'=f_0(a_0+\Delta)+f_1(a_1+\Delta)+\dots+f_n(a_{n-1}+\Delta)=s_0+\Delta(f_0+f_1+\dots f_{n-1})\) (这里的n为区间长度,由于从0开始需要-1)

同理\(s_1'=s_0+\Delta(f_1+f_2+\dots f_{n})\)

因此我们只需要预处理f的前缀和sumf,这样只用加上\(\Delta \times sumf(n-1)\)或\(\Delta \times (sumf(n)-sumf(0))\)

代码

  1. //https://blog.csdn.net/y752742355/article/details/80449062
  2. #include<iostream>
  3. #include<cstdio>
  4. #include<cstring>
  5. #define maxn 200000
  6. #define mod 1000000000
  7. using namespace std;
  8. int n,m;
  9. long long a[maxn+5];
  10. long long f[maxn+5];
  11. long long sumf[maxn+5];
  12. void ini(){
  13. f[0]=f[1]=1;
  14. for(int i=2;i<=maxn;i++){
  15. f[i]=(f[i-1]+f[i-2])%mod;
  16. }
  17. sumf[0]=1;
  18. for(int i=1;i<=maxn;i++){
  19. sumf[i]=(sumf[i-1]+f[i])%mod;
  20. }
  21. }
  22. struct node{
  23. int l;
  24. int r;
  25. long long s0;
  26. long long s1;
  27. int mark;
  28. int len(){
  29. return r-l+1;
  30. }
  31. }tree[maxn*4+5];
  32. inline long long fib(int n){//防止越界
  33. return n<0?0:f[n];
  34. }
  35. inline long long get_s(int pos,int n){//返回s_n(pos)
  36. return tree[pos].s0*fib(n-2)+tree[pos].s1*fib(n-1);
  37. }
  38. void push_up(int pos){
  39. tree[pos].s0=(tree[pos<<1].s0+get_s(pos<<1|1,tree[pos<<1].len()))%mod;
  40. tree[pos].s1=(tree[pos<<1].s1+get_s(pos<<1|1,tree[pos<<1].len()+1))%mod;
  41. }
  42. void build(int l,int r,int pos){
  43. tree[pos].l=l;
  44. tree[pos].r=r;
  45. if(l==r){
  46. tree[pos].s0=a[l]%mod;
  47. tree[pos].s1=a[l]%mod;
  48. return;
  49. }
  50. int mid=(l+r)>>1;
  51. build(l,mid,pos<<1);
  52. build(mid+1,r,pos<<1|1);
  53. push_up(pos);
  54. }
  55. void push_down(int pos){
  56. if(tree[pos].mark){
  57. tree[pos<<1].mark=(tree[pos<<1].mark+tree[pos].mark)%mod;
  58. tree[pos<<1|1].mark=(tree[pos<<1|1].mark+tree[pos].mark)%mod;
  59. tree[pos<<1].s0=(tree[pos<<1].s0+sumf[tree[pos<<1].len()-1]*tree[pos].mark%mod)%mod;
  60. tree[pos<<1].s1=(tree[pos<<1].s1+(sumf[tree[pos<<1].len()]-sumf[0])*tree[pos].mark%mod)%mod;
  61. tree[pos<<1|1].s0=(tree[pos<<1|1].s0+sumf[tree[pos<<1|1].len()-1]*tree[pos].mark%mod)%mod;
  62. tree[pos<<1|1].s1=(tree[pos<<1|1].s1+(sumf[tree[pos<<1|1].len()]-sumf[0])*tree[pos].mark%mod)%mod;
  63. tree[pos].mark=0;
  64. }
  65. }
  66. void update_add(int L,int R,long long v,int pos){
  67. if(L<=tree[pos].l&&R>=tree[pos].r){
  68. tree[pos].mark=(tree[pos].mark+v)%mod;
  69. tree[pos].s0=(tree[pos].s0+sumf[tree[pos].len()-1]*v%mod)%mod;
  70. tree[pos].s1=(tree[pos].s1+(sumf[tree[pos].len()]-sumf[0])*v%mod)%mod;
  71. return;
  72. }
  73. push_down(pos);
  74. int mid=(tree[pos].l+tree[pos].r)>>1;
  75. if(L<=mid) update_add(L,R,v,pos<<1);
  76. if(R>mid) update_add(L,R,v,pos<<1|1);
  77. push_up(pos);
  78. }
  79. void update_set(int upos,long long v,int pos){
  80. if(tree[pos].l==tree[pos].r){
  81. tree[pos].s0=v%mod;
  82. tree[pos].s1=v%mod;
  83. tree[pos].mark=0;
  84. return;
  85. }
  86. push_down(pos);
  87. int mid=(tree[pos].l+tree[pos].r)>>1;
  88. if(upos<=mid) update_set(upos,v,pos<<1);
  89. else update_set(upos,v,pos<<1|1);
  90. push_up(pos);
  91. }
  92. long long query(int L,int R,int pos){
  93. if(L<=tree[pos].l&&R>=tree[pos].r){
  94. int len=tree[pos].l-L;//注意合并答案时也要加上偏移值,和push_up一个原理
  95. if(len==0) return tree[pos].s0;
  96. else return get_s(pos,len);
  97. }
  98. push_down(pos);
  99. int mid=(tree[pos].l+tree[pos].r)>>1;
  100. long long ans=0;
  101. if(L<=mid) ans=(ans+query(L,R,pos<<1))%mod;
  102. if(R>mid) ans=(ans+query(L,R,pos<<1|1))%mod;
  103. return ans;
  104. }
  105. int main(){
  106. int opt,x,v,l,r,d;
  107. scanf("%d %d",&n,&m);
  108. ini();
  109. for(int i=1;i<=n;i++){
  110. scanf("%I64d",&a[i]);
  111. }
  112. build(1,n,1);
  113. for(int i=1;i<=m;i++){
  114. scanf("%d",&opt);
  115. if(opt==1){
  116. scanf("%d %d",&x,&v);
  117. update_set(x,v,1);
  118. }else if(opt==2){
  119. scanf("%d %d",&l,&r);
  120. printf("%I64d\n",query(l,r,1));
  121. }else{
  122. scanf("%d %d %d",&l,&r,&d);
  123. update_add(l,r,d,1);
  124. }
  125. }
  126. }

[Codeforces 316E3]Summer Homework(线段树+斐波那契数列)的更多相关文章

  1. 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 ...

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

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

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

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

  4. 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区间 ...

  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 446C - DZY Loves Fibonacci Numbers(斐波那契数列+线段树)

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

  7. codeforces316E3 Summer Homework(线段树,斐波那契数列)

    题目大意 给定一个n个数的数列,m个操作,有三种操作: \(1\ x\ v\) 将\(a_x\)的值修改成v $2\ l\ r\ $ 求 \(\sum_{i=l}^r x_i*f_{i-l}\) 其中 ...

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

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

  9. codeforces Codeforces Round #597 (Div. 2) Constanze's Machine 斐波拉契数列的应用

    #include<bits/stdc++.h> using namespace std; ]; ]; ; int main() { dp[] = ; scanf(); ); ; i< ...

随机推荐

  1. AOP切面详解

    一.spring-aop.xml文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns= ...

  2. 【LGR-062】洛谷10月月赛 III div.2 (A-C)

    前言 100+100+46+0=246pts 300多名 以后每次比赛都要有进步哦!qwq 小D与笔试 水题 Code #include<algorithm> #include<io ...

  3. [CF] E. Camels

    CF 2000 的dp题目还是有点难qwq 题意: 一行有\(n\)个空位,每个空位可以填\([1,4]\)的整数,要求: 1.有\(t\)个位置满足 \(ai−1<ai>ai+1(1&l ...

  4. CSP-S2019 停课日记

    前言 不想上文化课,于是就停课了 (雾) \(10.13\) 停课前一天 今天名义上是放假,所以不算停课. 老师和同学们听说我要停课,都十分的不舍.我啥也没说就悄悄溜到一中来了. \(10.14\) ...

  5. POJ-1390-Blocks (复杂区间DP)

    $ POJ~1390~~Blocks: $ (很难想的区间DP) $ solution: $ 很好的一道题目.看起来似乎很简单,当时一直认为可以用二维区间DP来完成,转移 $ n^3 $ . 后来发现 ...

  6. css图像拼合技术(精灵图)

    CSS图像拼合技术 1.图像拼合 图像拼合技术就是单个图像的集合. 有很多图片的网页可能会需要很多时间来加载和生成多个服务器的请求. 使用图像拼合会降低服务器的请求数量,并节省带宽. 图像拼合实例 有 ...

  7. django之路由的理解

    一:路由 简单的路由过程图: 1. 路由的定义位置 路由定义方式一:主路由和子路由分开定义 主路由的定义 urls.py from django.conf.urls import url from d ...

  8. MATLAB 和 armadillo 数据转换

    #include<iostream> #include<armadillo> int D=5; int M=4; int main() { arma::fmat x; x.ra ...

  9. Task4.文本表示:从one-hot到word2vec

    参考:https://blog.csdn.net/wxyangid/article/details/80209156 1.one-hot编码 中文名叫独热编码.一位有效编码.方法是使用N位状态寄存器来 ...

  10. Dubbo 在跨语言和协议穿透性方向的探索:支持 HTTP/2 gRPC

    Dubbo 在跨语言和协议穿透性方向上的探索:支持 HTTP/2 gRPC 和 Protobuf 本文整理自刘军在 Dubbo 成都 meetup 上分享的<Dubbo 在多语言和协议穿透性方向 ...