欢迎使用CSDN-markdown编辑器

来源:互联网 发布:哈登16 17赛季数据 编辑:程序博客网 时间:2024/05/20 08:02

原题目
E. DZY Loves Fibonacci Numbers
time limit per test4 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation

F1 = 1; F2 = 1; Fn = Fn - 1 + Fn - 2 (n > 2).
DZY loves Fibonacci numbers very much. Today DZY gives you an array consisting of n integers: a1, a2, …, an. Moreover, there are m queries, each query has one of the two types:

Format of the query “1 l r”. In reply to the query, you need to add Fi - l + 1 to each element ai, where l ≤ i ≤ r.
Format of the query “2 l r”. In reply to the query you should output the value of modulo 1000000009 (109 + 9).
Help DZY reply to all the queries.

Input
The first line of the input contains two integers n and m (1 ≤ n, m ≤ 300000). The second line contains n integers a1, a2, …, an (1 ≤ ai ≤ 109) — initial array a.

Then, m lines follow. A single line describes a single query in the format given in the statement. It is guaranteed that for each query inequality 1 ≤ l ≤ r ≤ n holds.

Output
For each query of the second type, print the value of the sum on a single line.

Examples
input
4 4
1 2 3 4
1 1 4
2 1 4
1 2 4
2 1 3
output
17
12

因为数据只有3e5,然后我就用分块写了,但是还有一个比较快的线段树的写法。
分块:因为两个斐波那契数列的和依然符合斐波那契的规律,所以对于某一块,只需要保存所有更新它的斐波那契的前两个值就可以了,那么可以根据这两个值,推出后面所有位要加的值,还要维护某一块里所有元素的和,这个只需要预处理1e5范围内的斐波那契的前缀和就可以了。

#include<bits/stdc++.h>using namespace std; const int N = 3e5+100; const int B = 555; const long long MOD= 1e9+9; struct node{    int x,y; };node b[555];int sum[N];int su[B];int n,q;int F[N];int sF[N];inline int read(){    int k=0;    char f=1;    char c=getchar();    for(;!isdigit(c);c=getchar() )        if(c=='-')            f=-1;    for(;isdigit(c);c=getchar() )        k=k*10+c-'0';    return k*f;}void add(int &x,int y){    x += y;    if(x >= MOD) x -= MOD;}int sub(int x,int y){    x -= y;    if(x < 0) x += MOD;    return x;}void init(){    F[1]= 1;    F[2] = 1;    sF[1] = 1;    sF[2] = 2;    for(int i= 3;i < N;i ++){        F[i] = (F[i-1]+F[i-2])%MOD;        add(sF[i],F[i]);        add(sF[i],sF[i-1]);    }}void update(int l,int r){    int lb = l/B,rb = r/B;    if(lb == rb){        for(int i= l;i <= r;i ++){            add(sum[i],F[i-l+1]);            add(su[lb],F[i-l+1]);        }        return ;    }    else{        for(int i = l;i < lb*B+B;i ++){            add(sum[i],F[i-l+1]);            add(su[lb],F[i-l+1]);        }        for(int i= rb*B;i <= r;i ++){            add(sum[i],F[i-l+1]);            add(su[rb],F[i-l+1]);        }        for(int i = lb+1;i < rb;i ++){            int sta = i*B;            add(b[i].x,F[sta-l+1-1]);            add(b[i].y,F[sta-l+1]);            add(su[i],sub(sF[sta-l+B],sF[sta-l]));        }    }}int query(int l,int r){    int lb = l/B,rb = r/B;    if(lb == rb){        int ans = 0;        int bef1 = b[lb].x,bef2 = b[lb].y;        for(int i = lb*B;i < l;i ++){            swap(bef1,bef2);            add(bef2,bef1);        }        for(int i = l;i <= r;i ++){            add(ans,bef2);            add(ans,sum[i]);            swap(bef1,bef2);            add(bef2,bef1);        }        return ans;    }    else{        int ans = 0;        int bef1 = b[lb].x,bef2 = b[lb].y;        for(int i = lb*B;i < l;i ++){            swap(bef1,bef2);            add(bef2,bef1);        }        for(int i = l;i < lb*B+B;i ++){            add(ans,bef2);            add(ans,sum[i]);            swap(bef1,bef2);            add(bef2,bef1);        }        //cout <<"!!!" << ans <<endl;        for(int i= lb+1;i < rb;i ++){            add(ans,su[i]);        }        //cout <<"!!!" << ans <<endl;        bef1 = b[rb].x,bef2 = b[rb].y;        for(int i= rb*B;i <= r;i ++){            add(ans,bef2);            add(ans,sum[i]);            swap(bef1,bef2);            add(bef2,bef1);        }        //cout <<"!!!" << ans <<endl;        return ans;    }}int main(){    init();    scanf("%d %d",&n,&q);    for(int i = 1;i <= n;i ++) {        //scanf("%d",&sum[i]);        sum[i] = read();        add(su[i/B],sum[i]);    }    for(int i= 1;i <= q;i ++){        int op,l,r;        op = read();        l = read();        r = read();        if(op == 1){            update(l,r);        }        else {            printf("%d\n",query(l,r));        }        //cout <<b[1].x << ' '<<b[1].y << endl;    }    return 0;}

线段树:这里要讲一个性质,如果知道某个数组符合斐波那契性质,和这个数组的前两个数,那么可以o(1)求出来这个数列的第x位的值,方法是,预处理斐波那契数列每一位包含多少个f(1)和f(2),然后乘一下就好了,然后对于线段树,每个节点记录以这加到一段的数列的前两项,对于左儿子,直接把数值加到左儿子上面就好了,对于右儿子用上面的方法求出再加到右儿子上。
对比两个方法,明显分块比较好写,但是时间复杂度略高,博主线段树还没写,,,以后补。

原创粉丝点击