CF718C Sasha and Array 题解

CF718C Sasha and Array

题面:

题面翻译
  • 在本题中,我们用 f i f_i fi 来表示第 i i i 个斐波那契数( f 1 = f 2 = 1 , f i = f i − 1 + f i − 2 ( i ≥ 3 ) f_1=f_2=1,f_i=f_{i-1}+f_{i-2}(i\ge 3) f1=f2=1,fi=fi1+fi2(i3))。
  • 给定一个 n n n 个数的序列 a a a。有 m m m 次操作,操作有两种:
    1. a l ∼ a r a_l\sim a_r alar 加上 x x x
    2. ( ∑ i = l r f a i )   m o d   ( 1 0 9 + 7 ) \displaystyle\left(\sum_{i=l}^r f_{a_i}\right)\bmod (10^9+7) (i=lrfai)mod(109+7)
  • 1 ≤ n , m ≤ 1 0 5 1\le n,m\le 10^5 1n,m105 1 ≤ a i ≤ 1 0 9 1\le a_i\le 10^9 1ai109
输出格式

For each query of the second type print the answer modulo 1 0 9 + 7 10^{9}+7 109+7.

样例 #1
样例输入 #1
5 4
1 1 2 1 1
2 1 5
1 2 4 2
2 2 4
2 1 5
样例输出 #1
5
7
9
提示

Initially, array a a a is equal to 1 1 1 , 1 1 1 , 2 2 2 , 1 1 1 , 1 1 1.

The answer for the first query of the second type is f ( 1 ) + f ( 1 ) + f ( 2 ) + f ( 1 ) + f ( 1 ) = 1 + 1 + 1 + 1 + 1 = 5 f(1)+f(1)+f(2)+f(1)+f(1)=1+1+1+1+1=5 f(1)+f(1)+f(2)+f(1)+f(1)=1+1+1+1+1=5.

After the query 1 2 4 2 array a a ais equal to 1 1 1, 3 3 3, 4 4 4, 3 3 3, 1 1 1.

The answer for the second query of the second type is f ( 3 ) + f ( 4 ) + f ( 3 ) = 2 + 3 + 2 = 7 f(3)+f(4)+f(3)=2+3+2=7 f(3)+f(4)+f(3)=2+3+2=7.

The answer for the third query of the second type is f ( 1 ) + f ( 3 ) + f ( 4 ) + f ( 3 ) + f ( 1 ) = 1 + 2 + 3 + 2 + 1 = 9 f(1)+f(3)+f(4)+f(3)+f(1)=1+2+3+2+1=9 f(1)+f(3)+f(4)+f(3)+f(1)=1+2+3+2+1=9.

矩阵加速递推大家都会!不会左转luogu模板

放到线段树上就好了!

每一个线段树上的点维护一个 [ f i f i − 1 ] \begin{bmatrix}f_i & f_{i - 1}\end{bmatrix} [fifi1]

因为在矩阵乘法中存在结合律,即:
A × B + A × C = A × ( B + C ) A \times B + A \times C = A \times (B + C) A×B+A×C=A×(B+C)

那么我们在线段树上push_up时,可以对两个节点做 + + + 操作

区间修改就用 l a z y   t a g lazy\ tag lazy tag 存矩阵快速幂的结果

初始化的时候用 [ 0 1 ] \begin{bmatrix}0 & 1\end{bmatrix} [01] 来表示 [ f 0 f − 1 ] \begin{bmatrix}f_0 & f_{-1}\end{bmatrix} [f0f1]

后面正常操作就可以了

AC-code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5+5,mod = 1e9 + 7;	
int rd() {
	int x = 0, w = 1;
	char ch = 0;
	while (ch < '0' || ch > '9') {
		if (ch == '-') w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = x * 10 + (ch - '0');
		ch = getchar();
	}
	return x * w;
}
void wt(int x) {
	static int sta[35];
	int f = 1;
	if(x < 0) f = -1,x *= f;
	int top = 0;
	do {
		sta[top++] = x % 10, x /= 10;
	} while (x);
	if(f == -1) putchar('-');
	while (top) putchar(sta[--top] + 48);
}
template<int N,int M,class T = long long>
struct matrix{
T m[N][M];
matrix() {memset(m,0,sizeof(m));}
matrix(bool _){memset(m,0,sizeof(m));for(int i = 0;i< N && i < M;i++) m[i][i] = 1;}
void unit() {memset(m,0,sizeof(m));for(int i = 0;i< N && i < M;i++) m[i][i] = 1;}
T* operator[] (const int pos) {return m[pos];}
bool empty() {
	for(int i = 0;i<N;i++)
		for(int j = 0;j<M;j++)
			if(i != j && m[i][j])
				return false;
	return true;
}
};

template<int N,int M,int R,class T = long long>
matrix<N,R,T> operator * (matrix<N,M,T> a,matrix<M,R,T> b) {
	matrix<N,R,T> c;
	for(int i = 0;i<N;i++)
		for(int j = 0;j<M;j++)
			for(int k = 0;k<R;k++)
				c[i][k] = (c[i][k] + a[i][j] * b[j][k] % mod) % mod;
	return c;
}

template<int N,int M,class T = long long>
matrix<N,M,T> operator + (matrix<N,M,T> a,matrix<N,M,T> b) {
	matrix<N,M> c;
	for(int i = 0;i<N;i++)
		for(int j = 0;j<M;j++)
			c[i][j] = (c[i][j] + a[i][j] + b[i][j]) % mod;
	return c;
}

template<int N,class T = long long>
matrix<N,N,T> qpow(matrix<N,N,T> x,int k) {
	matrix<N,N,T> re;
	re.unit();
	while(k){
		if(k & 1) re = re * x;
		x = x * x;
		k >>= 1;
	}
	return re;
}
matrix<2,2> base;
matrix<1,2> s;
int a[N],n,m;
namespace sgt{
matrix<1,2> t[N<<2];
matrix<2,2> lazy[N<<2];
#define ls (p << 1)
#define rs (ls | 1)
#define mid ((pl + pr) >> 1)
void push_up(int p) {t[p] = t[ls] + t[rs];}
void build(int p,int pl,int pr) {
	lazy[p].unit();
	if(pl == pr) {
		t[p] = s * qpow(base,a[pl]);
		return;
	}
	build(ls,pl,mid);
	build(rs,mid+1,pr);
	push_up(p);
}
void push_down(int p) {
	if(!lazy[p].empty()) {
		t[ls] = t[ls] * lazy[p];
		lazy[ls] = lazy[ls] * lazy[p];
		t[rs] = t[rs] * lazy[p];
		lazy[rs] = lazy[rs] * lazy[p];
		lazy[p].unit();
	}
}
matrix<2,2> upd;
void update(int p,int pl,int pr,int l,int r) {
	if(l <= pl && pr <= r) {
		t[p] = t[p] * upd;
		lazy[p] = lazy[p] * upd;
		return;
	}
	push_down(p);
	if(l <= mid) update(ls,pl,mid,l,r);
	if(r > mid) update(rs,mid+1,pr,l,r);
	push_up(p);
}

matrix<1,2> query(int p,int pl,int pr,int l,int r) {
	if(l <= pl && pr <= r) return t[p];
	push_down(p);
	if(r <= mid) return query(ls,pl,mid,l,r);
	else if(l > mid) return query(rs,mid+1,pr,l,r);
	else return query(ls,pl,mid,l,r) + query(rs,mid+1,pr,l,r);
}

}

void update() {
	int l = rd(),r = rd(),x = rd();
	sgt::upd.unit();
	sgt::upd = sgt::upd * qpow(base,x);
	sgt::update(1,1,n,l,r);
}

void query() {
	int l = rd(),r = rd();
	wt(sgt::query(1,1,n,l,r)[0][0]);
	putchar('\n');
}

signed main() {
	base[0][0] = base[0][1] = base[1][0] = 1;
	s[0][0] = 0,s[0][1] = 1;
	n = rd(),m = rd();
	for(int i = 1;i<=n;i++) a[i] = rd();
	sgt::build(1,1,n);
	while(m--) {
		int opt = rd();
		switch(opt) {
			case 1:
				update();
				break;
			case 2:
				query();
				break;
			default:
				puts("ERROR");
				exit(0);
				break;
		}
	}
	
	return 0;
}

不得不说,模板template真是好用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值