ZOJ 3772 Calculate the Function (线段树 + 矩阵)

思路分析:

遗憾不知道矩阵的构造。线段树上比较水的矩阵。。。


 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]   ]  。


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define maxn 100005
#define lson num<<1,s,mid
#define rson num<<1|1,mid+1,e
#define mod 1000000007
using namespace std;
typedef long long LL;

LL save[maxn];


struct Matrix
{
	LL data[2][2];
	Matrix()
	{
		memset(data,0,sizeof data);
	}
	Matrix operator * (const Matrix &a)
	{
		Matrix temp;

		for(int i=0;i<2;i++)
		for(int j=0;j<2;j++)
		for(int k=0;k<2;k++)
		temp.data[i][j] = ((data[i][k] * a.data[k][j]) + temp.data[i][j]) % mod;

		return temp;
	}
}tre[maxn<<2];


void pushup(int num)
{
    tre[num]=tre[num<<1|1]*tre[num<<1];
}

void build(int num,int s,int e)
{
    if(s==e)
    {
        tre[num].data[0][0]=1;
        tre[num].data[0][1]=save[s];
        tre[num].data[1][0]=1;
        tre[num].data[1][1]=0;
        return ;
    }
    int mid=(s+e)>>1;
    build(lson);
    build(rson);
    pushup(num);
}

Matrix query(int num,int s,int e,int l,int r)
{
    if(l<=s && r>=e)
    {
        return tre[num];
    }
    int mid=(s+e)>>1;
    if(r<=mid)return query(lson,l,r);
    else if(l>mid)return query(rson,l,r);
    else return query(rson,l,r)*query(lson,l,r);//顺序  attention!
}

int main()
{
    int T;
    int n,m;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);

        for(int i=1;i<=n;i++)scanf("%lld",&save[i]);
        build(1,1,n);
        while(m--)
        {
            int l,r;
            scanf("%d%d",&l,&r);

            if(r-l<2)printf("%d\n",save[r]);
            else
            {
                Matrix temp=query(1,1,n,l+2,r);
                LL ans=(temp.data[0][0]*save[l+1]+temp.data[0][1]*save[l])%mod;
                printf("%lld\n",ans);
            }
        }
    }
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值