zoukankan      html  css  js  c++  java
  • [原]zoj3772--【水题】线段树区间查询+矩阵乘法

    思路来源:http://blog.csdn.net/u013654696/article/details/23037407#comments


    【做浙大校赛的时候没有看这道题,事后做的。思路不是自己的,但代码是自己敲的,由于伦家不懂如何用TeX敲出如此优美的公式,所以具体请看上面的博客链接(づ ̄3 ̄)づ╭。虽然说思路对应下的代码很好敲,但如果在比赛中我肯定不一定想得到这么做。在这道题中,线段树的节点与区间存的不是具体的值,是对应的一个矩阵。做了这道题也让我明白了线段树原来还可以那么好用吖(づ ̄3 ̄)づ╭❤~。以后对于这样的矩阵都可以用线段树来呢,建矩阵线段树的时间复杂度是O(nlogn)。】


    总结:(ー`´ー)敲了一天,开始是体会错公式了,结果乘多了最后两个矩阵,后来又忘记取余了~~~这个逗比的教训告诉我们,做事要细心~~还有代码写矬了果断删掉重写!


    下面上AC代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define maxn 100010
    #define mod 1000000007
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    
    long long fun[maxn];
    long long num[maxn<<2];
    int n, m;
    
    class matrix{
     public:
       long long mat[2][2];
       matrix()
       {
         mat[0][0] = mat[1][1] = 1;
         mat[0][1] = mat[1][0] = 0;
       }
       matrix(long long a)
       {
         mat[0][0] = mat[1][0] = 1;
         mat[0][1] = a;
         mat[1][1] = 0;
       }
       matrix operator*(const matrix& m)const
       {
          matrix tmp;
          for(int i = 0; i < 2; i++)
            for(int j = 0; j < 2; j++){
              tmp.mat[i][j] = 0;
              for(int k = 0; k < 2; k++)
              {
                tmp.mat[i][j] += mat[i][k] * m.mat[k][j] % mod;
                tmp.mat[i][j] %= mod;
              }
            }
           return tmp;
       }
    };
    
    matrix sgt[maxn<<2];
    void pushup(int rt)
    {
      sgt[rt] = sgt[rt<<1|1] * sgt[rt<<1];  //注意矩阵乘的方向!!
    }
    
    void build(int l, int r, int rt)
    {
      if(l == r)
      {
        sgt[rt] = matrix(fun[l]);
        return;
      }
      int m = (l+r)>>1;
      build(lson);
      build(rson);
      pushup(rt);
    }
    
    matrix query(int l, int r, int rt, int L, int R)
    {
      if(L <= l && r <= R)
      {
        return sgt[rt];
      }
      int m = (l + r)>>1;
      matrix tmp;
      if(m < R) tmp = tmp * query(rson, L, R);         //注意矩阵乘的方向!!
      if(L <= m) tmp = tmp * query(lson, L, R);
      return tmp;
    }
    
    long long result(int l, int r, int rt, int L, int R)
    {
       if(R - L < 2)    //判断区间长度,小于等于二的直接输出右区间;
       {
         return fun[R];
       }
       matrix tmp;
       tmp = query(l, r, rt, L+2, R);
       long long a;
       a = tmp.mat[0][0] * fun[L+1] + tmp.mat[0][1] * fun[L];
       a %= mod;
       return a;
    }
    
    int main()
    {
      int T;
      cin>>T;
      while(T--)
      {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
          scanf("%d", &fun[i]);
        build(1, n, 1);
        long long a;
        for(int i = 0; i < m; i++)
        {
          a = 0;
          int c, d;
          scanf("%d%d", &c, &d);
          a = result(1, n, 1, c, d);
          printf("%d
    ",a);
        }
      }
      return 0;
    }


    作者:u011652573 发表于2014-4-8 21:24:15 原文链接
    阅读:54 评论:0 查看评论
  • 相关阅读:
    《构建之法》4、17章精读
    2016012005+小学四则运算练习软件项目报告
    Week2-作业一——《构建之法》三章精读之想
    虚拟到现实
    脚踏实地,莫问前程
    2016012010 赵瑞雪 散列函数的应用及其安全性
    结对项目报告
    《构建之法》第四章、第十七章读书笔记
    2016012010+小学四则运算练习软件项目报告
    《构建之法》第一、二、十六章读书笔记
  • 原文地址:https://www.cnblogs.com/ZiningTang/p/3834752.html
Copyright © 2011-2022 走看看