[CF446C] DZY Loves Fibonacci Numbers - 二次剩余,线段树维护等比数列
Description
在本题中,我们用 (f_i) 来表示第 (i) 个斐波那契数。维护一个序列 (a),长度为 (n),有 (m) 次操作:
1 l r
:对于 (lle ile r),将 (a_i) 加上 (f_{i-l+1})。2 l r
:求 (displaystyleleft(sum_{i=l}^ra_i ight)mod(10^9+9))。
Solution
通项公式 (a_n=frac{1}{sqrt{5}}[(frac{sqrt{5}+1}{2})^n-(frac{sqrt{5}-1}{2})^n]),由于 (sqrt 5) 在 (mod (10^9+9)) 下有二次剩余
因此转化为线段树维护等比数列
对于两个部分分别用一个线段树维护,这样公比是固定的,只需要一个 tag
表示当前节点加上的还未下传的首项即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
inline long long read()
{
long long x = 0;
int f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-')
f = -1;
for (; isdigit(ch); ch = getchar())
x = x * 10 + (ch ^ 48);
return x * f;
}
void print(long long x)
{
if (x < 0)
x = -x, putchar('-');
if (x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
const int mod = 1e9 + 9;
int qpow(int p, int q)
{
return (q & 1 ? p : 1) * (q ? qpow(p * p % mod, q / 2) : 1) % mod;
}
int inv(int p)
{
return qpow(p, mod - 2);
}
const int isq5 = 276601605;
const int modmod = mod * mod;
const int q1 = 691504013;
const int q2 = 308495997;
struct SegmentTree
{
int q; // common prop
int invb;
int *sum, *tag, *pw;
SegmentTree(int siz)
{
sum = new int[siz];
tag = new int[siz];
pw = new int[siz];
memset(sum, 0, sizeof sum);
memset(tag, 0, sizeof tag);
}
void presolve(int siz)
{
pw[0] = 1;
for (int i = 1; i < siz; i++)
pw[i] = pw[i - 1] * q % mod;
int b = 1 - q;
b = (b + modmod) % mod;
invb = inv(b);
}
void pushup(int p)
{
sum[p] = (sum[p * 2] + sum[p * 2 + 1]) % mod;
}
int qpow(int p)
{
return pw[p];
}
void put(int p, int l, int r, int v)
{
int len = r - l + 1;
int a = 1 - qpow(len);
a = (a + modmod) % mod;
sum[p] += v % mod * a % mod * invb;
sum[p] %= mod;
tag[p] += v;
tag[p] %= mod;
}
void pushdown(int p, int l, int r)
{
if (tag[p])
{
put(p * 2, l, (l + r) / 2, tag[p]);
put(p * 2 + 1, (l + r) / 2 + 1, r, tag[p] * qpow((l + r) / 2 - l + 1) % mod);
tag[p] = 0;
}
}
void modify(int p, int l, int r, int ql, int qr, int first)
{
if (l > qr || r < ql)
return;
if (l >= ql && r <= qr)
{
int a = first * qpow(l - ql) % mod;
put(p, l, r, a);
}
else
{
pushdown(p, l, r);
modify(p * 2, l, (l + r) / 2, ql, qr, first);
modify(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr, first);
pushup(p);
}
}
int query(int p, int l, int r, int ql, int qr)
{
if (l > qr || r < ql)
return 0;
if (l >= ql && r <= qr)
return sum[p];
pushdown(p, l, r);
return (query(p * 2, l, (l + r) / 2, ql, qr) + query(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr)) % mod;
}
};
const int N = 1e6 + 5;
int a[N], n, m;
signed main()
{
ios::sync_with_stdio(false);
n = read();
m = read();
for (int i = 1; i <= n; i++)
a[i] = read();
for (int i = 1; i <= n; i++)
a[i] += a[i - 1];
SegmentTree seg1(2e6), seg2(2e6);
seg1.q = q1;
seg2.q = q2;
seg1.presolve(2e6);
seg2.presolve(2e6);
for (int i = 1; i <= m; i++)
{
int op, l, r;
op = read();
l = read();
r = read();
if (op == 1)
{
seg1.modify(1, 1, n, l, r, q1);
seg2.modify(1, 1, n, l, r, q2);
}
else
{
int ans1 = seg1.query(1, 1, n, l, r);
int ans2 = seg2.query(1, 1, n, l, r);
int ans = (ans1 - ans2) * isq5 + a[r] - a[l - 1];
ans %= mod;
ans += mod;
ans %= mod;
print(ans);
putchar('
');
}
}
}