斐波那契+线段树

写太丑了被卡常了,先码。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#define mid ((l+r)>>1)
#define lc x<<1
#define rc x<<1|1
const int maxn=1e6+10;
typedef long long LL;
const LL mod=1e9+1;
LL cs[maxn],n,m,l,r,opt,sgt[maxn<<2],lz[maxn<<2][2];
using namespace std;
inline LL read(){
  LL ret=0,f=1; char ch=getchar();
  while((ch!=‘-‘)&&(ch>‘9‘||ch<‘0‘)) ch=getchar();
  if(ch==‘-‘) f=-1,ch=getchar();
  for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) ret=ret*10+ch-‘0‘;
  return ret;
}
struct jz{
   LL a[3][3];
   friend jz operator *(const jz&A,const jz&B){
         jz ret; memset(ret.a,0,sizeof(ret.a ));
      for(int i=0;i<=2;i++)
      for(int j=0;j<=2;j++)
      for(int k=0;k<=2;k++)
       ret.a[i][j]=(ret.a[i][j]+A.a[i][k]*B.a[k][j]%mod)%mod;
      return ret;
   }
}fi[maxn];
struct T{
   LL b[3];
   friend T operator *(const T&A,const jz&B){
     T ret; memset(ret.b,0,sizeof(ret.b));
     for(int i=0;i<=2;i++)
     for(int k=0;k<=2;k++)
     ret.b[i]=(ret.b[i]+A.b[k]*B.a[k][i]%mod)%mod;
     return ret;
   }
}tmp;
void down(int x,int l_len,int r_len){
    (lz[lc][0]+=lz[x][0])%=mod;
    (lz[lc][1]+=lz[x][1])%=mod;
    tmp.b[0]=lz[x][0];
    tmp.b[1]=tmp.b[2]=lz[x][1];
    tmp=tmp*fi[l_len];
    (sgt[lc]+=tmp.b[2])%=mod;
    LL tt=tmp.b[2];
    tmp=tmp*fi[1];
    (lz[rc][0]+=tmp.b[0])%=mod;
    (lz[rc][1]+=tmp.b[1])%=mod;
    tmp=tmp*fi[r_len];
    sgt[rc]+=((tmp.b[2]-tt)%mod+mod)%mod;
    lz[x][0]=lz[x][1]=0;
}
void build(int x,int l,int r){
    if(l==r) {sgt[x]=cs[l];return;}
    build(lc,l,mid); build(rc,mid+1,r);
    sgt[x]=sgt[lc]+sgt[rc];
}
void add(int x,int l,int r,int ql,int qr,LL af,LL as){
    if(l>=ql&&r<=qr){
       (lz[x][0]+=af)%=mod;
       (lz[x][1]+=as)%=mod;
       tmp.b[0]=af;
       tmp.b[1]=tmp.b[2]=as;
       tmp=tmp*fi[r-l];
       (sgt[x]+=tmp.b[2])%=mod;
       return;
    }
    if(lz[x][0]||lz[x][1]) down(x,mid-l,r-mid-1);
    if(ql<=mid) add(lc,l,mid,ql,qr,af,as);
    if(qr>mid){
      if(ql>mid) add(rc,mid+1,r,ql,qr,af,as);
      else{
       tmp.b[0]=af;
       tmp.b[1]=tmp.b[2]=as;
       tmp=tmp*fi[mid-max(l,ql)+1];
       add(rc,mid+1,r,ql,qr,tmp.b[0],tmp.b[1]);
      }
    }
    sgt[x]=(sgt[lc]+sgt[rc])%mod;
}
LL query(int x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr) return sgt[x];
    if(lz[x][0]||lz[x][1]) down(x,mid-l,r-mid-1);
    if(qr<=mid) return query(lc,l,mid,ql,qr);
    if(ql>mid) return query(rc,mid+1,r,ql,qr);
    return (query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr))%mod;
}
int main()
{
    //freopen("fibnacci.in","r",stdin);
    //freopen("fibnacci.out","w",stdout);
   n=read(); m=read();
   for(int i=1;i<=n;i++) cs[i]=read();
   build(1,1,n);
   fi[0].a[0][0]=fi[0].a[1][1]=fi[0].a[2][2]=1;
   fi[1].a[0][1]=fi[1].a[0][2]=fi[1].a[1][0]=fi[1].a[1][1]=fi[1].a[1][2]=fi[1].a[2][2]=1;
   for(int i=2;i<=n;i++) fi[i]=fi[i-1]*fi[1];
   while(m--){
    opt=read(); l=read(); r=read();
    if(opt==1) add(1,1,n,l,r,0,1);
    else printf("%lld\n",query(1,1,n,l,r));
   }
   return 0;
}

时间: 2024-10-07 03:50:47

斐波那契+线段树的相关文章

hdu 4893 Wow! Such Sequence!(线段树功能:单点更新,区间更新相邻较小斐波那契数)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 --------------------------------------------------------------------------------------------------------------------------------------------

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

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

题目大意:给出一个长度为n的数列a. 对于一个询问lj和rj.将a[lj]到a[rj]从小到大排序后并去重.设得到的新数列为b,长度为k,求F1*b1+F2*b2+F3*b3+...+Fk*bk.当中F为斐波那契数列.F1=F2=1.对每一个询问输出答案模m. 区间查询离线 用莫队算法 开棵权值线段树,然后用斐波那契的性质update F(n+m)=F(n+1)*F(m)+F(n)*F(m-1); #include<cstdio> #include<cstdlib> #includ

Codeforces Round #FF (Div. 2) E. DZY Loves Fibonacci Numbers(斐波那契的定理+线段树)

/* 充分利用了菲波那切数列的两条定理: ①定义F[1] = a, F[2] = b, F[n] = F[n - 1] + F[n - 2](n≥3). 有F[n] = b * fib[n - 1] + a * fib[n - 2](n≥3),其中fib[i]为斐波那契数列的第 i 项. ②定义F[1] = a, F[2] = b, F[n] = F[n - 1] + F[n - 2](n≥3). 有F[1] + F[2] + -- + F[n] = F[n + 2] - b 这题还有一个事实,

Benelux Algorithm Programming Contest 2014 Final ACM-ICPC Asia Training League 暑假第一阶段第二场 E. Excellent Engineers-单点更新、区间最值-线段树 G. Growling Gears I. Interesting Integers-类似斐波那契数列-递推思维题

先写这几道题,比赛的时候有事就只签了个到. E. Excellent Engineers 传送门: 这个题的意思就是如果一个人的r1,r2,r3中的某一个比已存在的人中的小,就把这个人添加到名单中. 因为是3个变量,所以按其中一个变量进行sort排序,然后,剩下的两个变量,一个当位置pos,一个当值val,通过线段树的单点更新和区间最值操作,就可以把名单确定. 代码: 1 //E-线段树 2 #include<iostream> 3 #include<cstdio> 4 #incl

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

Description ? 看题戳我 给你一个序列,要求支持区间加斐波那契数列和区间求和.\(~n \leq 3 \times 10 ^ 5, ~fib_1 = fib_2 = 1~\). Solution ? 先来考虑一段斐波那契数列如何快速求和,根据性质有 \[ \begin {align} fib_n &= fib_{n - 1} + fib_{n - 2} \ &= fib_ {n - 2} + fib_{n - 3} + fib_{n - 2} \ &= fib_{n -

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

题目大意 给定一个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

笔试算法题(46):简介 - 二叉堆 &amp; 二项树 &amp; 二项堆 &amp; 斐波那契堆

二叉堆(Binary Heap) 二叉堆是完全二叉树(或者近似完全二叉树):其满足堆的特性:父节点的值>=(<=)任何一个子节点的键值,并且每个左子树或者右子树都是一 个二叉堆(最小堆或者最大堆):一般使用数组构建二叉堆,对于array[i]而言,其左子节点为array[2*i],其右子节点为 array[2*i+1]:二叉堆支持插入,删除,查找最大(最小)键值的操作,但是合并二叉堆的复杂度较高,时间复杂度为O(N):但是二项堆或者斐波 那契堆则仅需要O(logN): 二项树(Binomial

coderfoces446c (斐波那契数列)

题目描述: 区间增值,但是每一项增加的值为Fi - l + 1,F[i]为斐波那契数列,求区间和? 考虑线段树,刚开始想用斐波那契数列的前n项和,可是推不出来,考虑到每个区间的增值序列都是一段斐波那契数列,他们的和是否有什么特性呢? 发现如果前两项为a和b的话,那么,a,b,a+b,a+2b,2a+3b,3a+5b; a和b前的系数为斐波那契数列(后一项为前两项之和, 设F[k]表示以a,b开头的第k项的值,s[k]代表以a和b开头的前k项和 F[k]=a*f[k-2]+b*f[k-1]; F[