题意:给出一个序列a,给出两种操作,操作1:对a数组中
[
l
,
r
]
[l,r]
[l,r]范围的内的数加上一个数x,操作2:查询
[
l
,
r
]
[l,r]
[l,r]范围内的
f
[
a
[
i
]
]
f[a[i]]
f[a[i]],其中
f
[
x
]
f[x]
f[x],是指第x个斐波那契数。
思路:显然对于第一种操作,这里需要用到区间修改,所以要用到懒标记的线段树,对于第二种操作,可以很快地想到用矩阵加速递推式。于是开一个结点信息是矩阵的线段树,维护每个点的斐波那契和,懒标记写成转移矩阵的幂次,就可以非常清晰做出来这题。
const int N = 2, M = 1e5 + 50;
int w[M];
struct mat
{
ll A[N][N];
mat() { memset(A, 0, sizeof A); }
mat operator * (const mat &b) const
{
mat tmp;
f(i,0,N-1)
f(j,0,N-1)
f(k,0,N-1)
tmp.A[i][k] = (tmp.A[i][k] + 1ll * A[i][j] * b.A[j][k]) %mod;
return tmp;
}
}tr[M << 2],lz[M<<2],f,A1;
mat jzksm(mat a, int n)
{
mat tmp;
tmp.A[0][0]=tmp.A[1][1]=1;
while (n)
{
if (n & 1) tmp= tmp * a;
a=a*a;
n >>= 1;
}
return tmp;
}
void pushup(int u)
{
tr[u].A[0][0] = (tr[u << 1].A[0][0] + tr[u << 1 | 1].A[0][0]) % mod;
tr[u].A[0][1] = (tr[u << 1].A[0][1] + tr[u << 1 | 1].A[0][1]) % mod;
}
void pushdown(int u)
{
tr[u<<1]= tr[u<<1]*lz[u];
lz[u << 1] = lz[u << 1] * lz[u];
tr[u << 1 | 1] = tr[u << 1 | 1] * lz[u];
lz[u << 1 | 1] = lz[u << 1 | 1] * lz[u];
lz[u].A[0][0] = 1, lz[u].A[1][1] = 1, lz[u].A[0][1] = 0, lz[u].A[1][0] = 0;
}
void build(int i, int l, int r)
{
if (l == r)
{
tr[i].A[0][0] = 1;tr[i].A[0][1] = 1;tr[i].A[1][0] = 1;
tr[i]=jzksm(tr[i], w[l]-1);
tr[i] = A1 * tr[i];
lz[i].A[0][0] = lz[i].A[1][1] = 1;
return;
}
lz[i].A[0][0] = lz[i].A[1][1] = 1;
int mid = (l + r) >> 1;
build(i << 1, l, mid),build(i << 1 | 1, mid + 1, r);
pushup(i);
}
void modify(int u, int l, int r, int L, int R, mat w)
{
if (l >= L && r <= R)
{
tr[u] = tr[u] * w;
lz[u] = lz[u] * w;
return;
}
else
{
pushdown(u);
int mid = l + r >> 1;
if (L <= mid)modify(u << 1, l, mid, L, R, w);
if (R > mid)modify(u << 1 | 1, mid + 1, r, L, R, w);
pushup(u);
}
}
ll query(int u, int l, int r,int L,int R)//当前查询范围,目标查询范围
{
if (l >= L && r <= R)return tr[u].A[0][0];
pushdown(u);
int mid = l+r>> 1;
ll sum = 0;
if (L <= mid)sum =sum + query(u << 1,l,mid,L,R);
if (R > mid)sum += query(u << 1 | 1,mid+1,r,L,R);
return sum %mod;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
f.A[0][0] = 1;
f.A[0][1] = 1;
f.A[1][0] = 1;
A1.A[0][0] = 1;
int n, q;
cin >> n >> q;
f(i, 1, n)w[i] = in();
build(1, 1, n);
while (q--)
{
int op = in();
if (op == 1)
{
int l = in(), r = in(), x = in();
f=jzksm(f, x);
modify(1, 1, n, l, r, f);
f.A[0][0] = f.A[0][1] = f.A[1][0] = 1;f.A[1][1] = 0;
}
else
{
int l = in(), r = in();
printf("%lld\n", query(1, 1, n, l, r));
}
}
return 0;
}