一.题目链接:

ZOJ-3772

二.题目大意:

给 n 个数 a[1~n]

定义  如下:

 

对于每次查询,给出区间端点  和  的值

求出  .

三.分析:

由递推式可得

   

  

 

所以我们可以建一颗线段树,节点值存为矩阵,父节点就存为矩阵乘积.

然后进行区间查询  即可.

查询得到的矩阵再乘以矩阵  取(0,0)元素即可.

因为线段树的遍历顺序,所以不必担心矩阵相乘的顺序会错误.

四.代码实现:

#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-6
#define pi acos(-1.0)
#define ll long long int
using namespace std;

const int M = (int)1e5;
const ll mod = 1000000007;

struct node1
{
    ll D[2][2];
};

struct node2
{
    int l;
    int r;
    node1 T;
}tree[M * 4 + 5];

ll a[M + 5];

node1 ans;

node1 juzhen(node1 s1, node1 s2)
{
    node1 s3;
    for(int i = 0; i < 2; ++i)
        for(int j = 0; j < 2; ++j)
            s3.D[i][j] = 0;
    for(int i = 0; i < 2; ++i)
    {
        for(int j = 0; j < 2; ++j)
        {
            for(int k = 0; k < 2; ++k)
            {
                s3.D[i][j] = (s3.D[i][j] + s1.D[i][k] * s2.D[k][j] % mod) % mod;
            }
        }
    }
    return s3;
}

void build(int k, int l, int r)
{
    tree[k].l = l;
    tree[k].r = r;
    if(tree[k].l == tree[k].r)
    {
        tree[k].T.D[0][0] = 1;
        tree[k].T.D[0][1] = 1;
        tree[k].T.D[1][0] = a[tree[k].l];
        tree[k].T.D[1][1] = 0;
        return;
    }
    int mid = (tree[k].l + tree[k].r) / 2;
    build(k * 2, l, mid);
    build(k * 2 + 1, mid + 1, r);
    tree[k].T = juzhen(tree[k * 2].T, tree[k * 2 + 1].T);
}

void query(int k, int l, int r, int a, int b)
{
    if(tree[k].l >= a && tree[k].r <= b)
    {
        ans = juzhen(ans, tree[k].T);
        return;
    }
    int mid = (tree[k].l + tree[k].r) / 2;
    if(a <= mid)
        query(k * 2, l, mid, a, b);
    if(mid < b)
        query(k * 2 + 1, mid + 1, r, a, b);
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n, m;
        scanf("%d %d", &n, &m);
        for(int i = 1; i <= n; ++i)
            scanf("%lld", &a[i]);
        build(1, 1, n);
        while((m--) > 0)
        {
            int l, r;
            scanf("%d %d", &l, &r);
            if(r - l < 2)
            {
                printf("%lld\n", a[r]);
                continue;
            }
            ans.D[0][0] = 1;
            ans.D[0][1] = 0;
            ans.D[1][0] = 0;
            ans.D[1][1] = 1;
            query(1, 1, n, l + 2, r);
            node1 s;
            s.D[0][0] = a[l + 1];
            s.D[0][1] = a[l];
            s.D[1][0] = 0;
            s.D[1][1] = 0;
            ans = juzhen(s, ans);
            printf("%lld\n", ans.D[0][0] % mod);
        }
    }
    return 0;
}