[原]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 查看评论
原文地址:https://www.cnblogs.com/ZiningTang/p/3834752.html