zoukankan      html  css  js  c++  java
  • 线段树 + 矩阵 --- ZOJ 3772 Calculate the Function

     Calculate the Function

    Problem's Link:   http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3772


    Mean: 

     

    analyse:

    简单的线段树维护矩阵。

    矩阵乘法的结合律(a * b * c == a * (b * c)),注意矩阵乘法不满足分配率(a *b != b * a)。

     

    令 M[x] = [1 A[x]]
                  [1     0 ] ,
    那么有 [ F[R] ] = M[R] * M[R-1] * ... * M[L+2] * [F[L+1]]
              [F[R-1]]                                                   [ F[L] ] 

     

    线段树节点维护上边等式右边前n - 1项的乘值(假设等式右边有n项)。每次询问O(log(n))。

    Time complexity: O(n*logn)

    Source code: 

    /*
    * this code is made by crazyacking
    * Verdict: Accepted
    * Submission Date: 2015-05-25-20.57
    * Time: 0MS
    * Memory: 137KB
    */
    #include <queue>
    #include <cstdio>
    #include <set>
    #include <string>
    #include <stack>
    #include <cmath>
    #include <climits>
    #include <map>
    #include <cstdlib>
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    #define  LL long long
    #define  ULL unsigned long long
    using namespace std;
    
    const int MAXN = 100100;
    const int MOD = 1000000007;
    struct Mat
    {
        long long m[2][2];
        Mat()
        {
                memset(m, 0, sizeof(m));
        }
        Mat operator * (const Mat &b)
        {
            Mat temp;
            for(int i = 0; i < 2; i++)
                for(int j = 0; j < 2; j++)
                    for(int k = 0; k < 2; k++)
                        temp.m[i][j] = ((m[i][k] * b.m[k][j]) + temp.m[i][j]) % MOD;
            return temp;
        }
    };
    
    struct Node
    {
        int l, r;
        Mat mat;
    };
    Node node[MAXN << 2];
    int a[MAXN];
    
    void Build(int rt, int l, int r)
    {
        int m;
        node[rt].l = l;
        node[rt].r = r;
        if(l == r)
        {
            node[rt].mat.m[0][0] = 1;
            node[rt].mat.m[0][1] = a[l];
            node[rt].mat.m[1][0] = 1;
            node[rt].mat.m[1][1] = 0;
        }
        else
        {
            m = (l + r) >> 1;
            Build(rt << 1, l, m);
            Build(rt << 1 | 1, m + 1, r);
            node[rt].mat = node[rt << 1 | 1].mat * node[rt << 1].mat;//注意顺序
        }
    
    }
    Mat Query(int rt, int ql, int qr)
    {
        int m;
        if(ql == node[rt].l && node[rt].r == qr)
            return node[rt].mat;
        else
        {
            m = (node[rt].l + node[rt].r) >> 1;
            if(qr <= m)
                return Query(rt << 1, ql, qr);
            else if(ql > m)
                return Query(rt << 1 | 1, ql, qr);
            else
                return Query(rt << 1 | 1, m + 1, qr) * Query(rt << 1, ql, m);//注意顺序
        }
    }
    int T, n, m, ql, qr;
    
    int main()
    {
        scanf("%d", &T);
        while(T--)
        {
            Mat res, f;
            scanf("%d%d",&n, &m);
            for(int i = 1; i <= n; i++)
                scanf("%d", &a[i]);
            Build(1, 1, n);
            for(int i = 1; i<= m; i++)
            {
                scanf("%d%d", &ql, &qr);
                if(qr - ql >= 2)
                {
                    f.m[0][0] = a[ql + 1];
                    f.m[1][0] = a[ql];
                    res = Query(1, ql + 2, qr) * f;
                    printf("%d
    ", res.m[0][0]);
                }
                else
                    printf("%d
    ", a[qr]);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    JS站点
    1011 World Cup Betting (20分)
    1007 Maximum Subsequence Sum (25分)(动态规划DP)
    1006 Sign In and Sign Out (25分)
    1005 Spell It Right (20分)
    1004 Counting Leaves (30分)(DFS)
    1003 Emergency (25分)(Dijkstra算法)
    1002 A+B for Polynomials (25分)
    1001 A+B Format (20分)
    canvas
  • 原文地址:https://www.cnblogs.com/crazyacking/p/4529012.html
Copyright © 2011-2022 走看看