E. Sasha and Array——矩陣+線段樹

E.Sasha and Array

很神奇的一道題

題意大概就是支持區間加,然後求區間和。。。

區間和的求法是 sigma(i,l,r) f[i]  f[i]表示斐波那契序列第i項

例如一個區間的數字是1 2 3 4 5 6 

那麼其和爲1+1+2+3+5+8=20


看到數據範圍。。那斐波那契肯定不能離線處理了,只能是用矩陣去算

那我們如果給一個數+x,相當於讓他再乘x次,這樣就可以用線段樹求解了


那麼問題出現了,我們的lazy標記要怎麼打??

不打的話顯然會退化到n^2,打的話這個和可不是一個整體


然而有一個東西叫做。。分配律

對於矩陣A,B,C

A*C+B*C=(A+B)*C

所以我們在線段樹的每個節點上存下當前的一個矩陣總和的話,好像沒什麼毛病?答案那一項也就是我們原來想的那個答案

然後lazy標記我們可以打成是一個轉移矩陣的^x次,這樣我們就可以很輕鬆的Push下去了


(說實話這是第一次做題把矩陣的分配律用進去。。。。。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#include <ctime>
#include <vector>
#define inf 1e9
#define ll long long
#define For(i,j,k) for(ll i=j;i<=k;i++)
#define Dow(i,j,k) for(ll i=k;i>=j;i--)
using namespace std;
ll lson[500001],rson[500001],L[500001],R[500001],a[500001],rt,tot,n,k,ans;
ll mo=1e9+7;
struct mat
{
	ll cube[3][3];
	mat(){cube[1][1]=cube[2][2]=0;cube[1][2]=cube[2][1]=0;}
	mat operator *(const mat &tx)const
	{
		mat tmp;
		For(k,1,2)
			For(i,1,2)	if(cube[i][k])
				For(j,1,2)	tmp.cube[i][j]+=(cube[i][k]*tx.cube[k][j])%mo,tmp.cube[i][j]%=mo;
		return tmp;
	}	
	mat operator +(const mat &tx)const
	{
		mat tmp;
		For(i,1,2)	For(j,1,2)	tmp.cube[i][j]=cube[i][j]+tx.cube[i][j],tmp.cube[i][j]%=mo;
		return tmp;
	}	
}tag[500001],sum[500001],one,zero;
inline mat ksm(mat x,ll y){if(y==0)	return zero;mat sum=x;y--;for(;y;y/=2){if(y&1)sum=sum*x;x=x*x;}return sum;}
inline void down(ll x)
{
	sum[lson[x]]=sum[lson[x]]*tag[x];
	sum[rson[x]]=sum[rson[x]]*tag[x];
	tag[lson[x]]=tag[lson[x]]*tag[x];
	tag[rson[x]]=tag[rson[x]]*tag[x];
	tag[x]=zero;
}
inline void build(ll &x,ll l,ll r)
{
	x=++tot;
	sum[x]=zero;tag[x]=zero;
	L[x]=l;R[x]=r;
	if(l==r)	
	{
		sum[x]=ksm(one,a[l]-1);
		return;
	}
	ll mid=(l+r)>>1;
	build(lson[x],l,mid);build(rson[x],mid+1,r);
	sum[x]=sum[lson[x]]+sum[rson[x]];
}
inline void update(ll x,ll l,ll r,mat v)
{
	if(l<=L[x]&&R[x]<=r)
	{
		tag[x]=tag[x]*v;sum[x]=sum[x]*v;
		return;
	}
	down(x);
	if(l<=R[lson[x]])	update(lson[x],l,r,v);
	if(r>=L[rson[x]])	update(rson[x],l,r,v);
	sum[x]=sum[lson[x]]+sum[rson[x]];
}
inline ll query(ll x,ll l,ll r)
{
	if(l<=L[x]&&R[x]<=r)
		return sum[x].cube[1][1];
	down(x);
	ll ret=0;
	if(l<=R[lson[x]])	ret+=query(lson[x],l,r),ret%=mo;
	if(r>=L[rson[x]])	ret+=query(rson[x],l,r),ret%=mo;
	sum[x]=sum[lson[x]]+sum[rson[x]];
	return ret;
}
int main()
{
	one.cube[1][1]=one.cube[1][2]=one.cube[2][1]=1;one.cube[2][2]=0;
	zero.cube[1][1]=zero.cube[2][2]=1;zero.cube[1][2]=zero.cube[2][1]=0;
	scanf("%lld%lld",&n,&k);
	For(i,1,n)	scanf("%lld",&a[i]);
	build(rt,1,n);
	For(i,1,k)
	{
		ll opt;
		scanf("%lld",&opt);
		if(opt==1)
		{
			ll x,y,v;
			scanf("%lld%lld%lld",&x,&y,&v);
			mat tmp=ksm(one,v);
			update(1,x,y,tmp);	
		}
		else
		{
			ll x,y;
			
			scanf("%lld%lld",&x,&y);
			ans=query(1,x,y);
			printf("%lld\n",ans);
		}
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章