1. 程式人生 > 實用技巧 >CF718C Sasha and Array

CF718C Sasha and Array

前言

一道打著很舒服的 線段樹 + 矩陣加速 的題

題目

洛谷

CF

講解

1e9範圍的斐波拉契數直接想到矩陣加速

而區間和就讓我們想到線段樹,用矩陣轉移

具體的,維護 \(f_{a[i]},f_{a[i+1]}\)與lazy矩陣 即可實現轉移

程式碼

//12252024832524
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; 

typedef long long LL;
const int MAXN = 100005;
const int MOD = 1e9 + 7;
int n,m;
int a[MAXN];

int Read()
{
	int x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
void Put1(int x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
void Put(int x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x);
	if(c >= 0) putchar(c);
}
template <typename T>T Max(T x,T y){return x > y ? x : y;}
template <typename T>T Min(T x,T y){return x < y ? x : y;}
template <typename T>T Abs(T x){return x < 0 ? -x : x;}

void AM(int &x,int y) 
{
	x += y;
	if(x >= MOD) x -= MOD;
}

struct Matrix
{
	int n,m;
	int a[2][2];
	
	Matrix(){memset(a,0,sizeof(a));}
	
	Matrix operator + (const Matrix C)const{
		Matrix ret;
		ret.n = n;ret.m = m;
		for(int i = 0;i < n;++ i)
			for(int j = 0;j < m;++ j)
				AM(ret.a[i][j],C.a[i][j]),AM(ret.a[i][j],a[i][j]);
		return ret;
	}
	
	Matrix operator * (const Matrix C)const{
		Matrix ret;
		ret.n = n;ret.m = C.m;
		for(int i = 0;i < n;++ i)
			for(int k = 0;k < m;++ k)
				if(a[i][k])
					for(int j = 0;j < C.m;++ j)
						ret.a[i][j] = (ret.a[i][j] + 1ll * a[i][k] * C.a[k][j]) % MOD;
		return ret;
	}
}I,A,B;

Matrix qpow(Matrix di,Matrix x,int y)
{
	Matrix ret = di;
	while(y)
	{
		if(y & 1) ret = ret * x;
		x = x * x;
		y >>= 1;
	}
	return ret;
}
int fib(int x)
{
	if(x <= 1) return A.a[0][x];
	else return qpow(A,B,x-1).a[0][1];
}

struct SegmentTree
{
	struct node
	{
		int l,r;
		Matrix val,lz;
	}t[MAXN << 2];
	
	void update(int x)
	{
		t[x].val = t[x<<1].val + t[x<<1|1].val;
	}
	
	void down(int x)
	{
		t[x<<1].lz = t[x].lz * t[x<<1].lz;
		t[x<<1|1].lz = t[x].lz * t[x<<1|1].lz;
		t[x<<1].val = t[x<<1].val * t[x].lz;
		t[x<<1|1].val = t[x<<1|1].val * t[x].lz;
		t[x].lz = I;
	}
	
	void Add(int x,int l,int r,Matrix ad)
	{
		if(l <= t[x].l && t[x].r <= r)
		{
			t[x].lz = t[x].lz * ad;
			t[x].val = t[x].val * ad;
			return;
		}
		down(x);
		int mid = (t[x].l + t[x].r) >> 1;
		if(l <= mid) Add(x<<1,l,r,ad);
		if(mid+1 <= r) Add(x<<1|1,l,r,ad);
		update(x);
	}
	
	void Build(int x,int l,int r)
	{
		t[x].l = l;t[x].r = r;
		t[x].val.n = 1;t[x].val.m = 2;
		t[x].lz = I;
		if(l == r) 
		{
			t[x].val.a[0][0] = fib(a[l]-1);
			t[x].val.a[0][1] = fib(a[l]);
			return;
		}
		int mid = (l+r) >> 1;
		Build(x<<1,l,mid); Build(x<<1|1,mid+1,r);
		update(x);
	}
	int query(int x,int l,int r)
	{
		if(l <= t[x].l && t[x].r <= r)
			return t[x].val.a[0][1];
		down(x);
		int mid = (t[x].l + t[x].r) >> 1,ret = 0;
		if(l <= mid) AM(ret,query(x<<1,l,r));
		if(mid+1 <= r) AM(ret,query(x<<1|1,l,r));
		return ret;
	}
}st;

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	I.n = I.m = 2;
	I.a[0][0] = I.a[1][1] = 1;
	A.n = 1;A.m = 2;
	A.a[0][0] = 0,A.a[0][1] = 1;
	B.n = B.m = 2;
	B.a[0][1] = B.a[1][1] = B.a[1][0] = 1;
	n = Read(); m = Read();
	for(int i = 1;i <= n;++ i) a[i] = Read();
	st.Build(1,1,n);
	while(m--)
	{
		int opt = Read(),l = Read(),r = Read();
		if(opt == 1) st.Add(1,l,r,qpow(I,B,Read()));
		else Put(st.query(1,l,r),'\n');
	}
	return 0;
}