标签:
F表示斐波那契数列,给定原始数列,每次操作对[l,r]内的数加上F[i - l + 1](l≤i≤r),或询问区间[l,r]的和。
我们发现对于修改操作可以O(1)实现。只要用一新数组D记录,对于[l, r]的修改,将D[l] += 1, D[r + 1] -= F[r - l + 2], D[r + 2] -= F[r - l + 1],然后询问的时候令D[i] += D[i - 1] + D[i - 2]。D就是总的修改和。然而询问要O(n)。我们怎样才能平衡修改和询问呢。这要用到平衡规划的思想, 每修改k次才重构一次D数组。对于一次询问,答案就是上一次重构的D数组和未将D操作的修改的总贡献。k取根号n的话,复杂度是O(√nm)。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 7 const int N = 1e5 + 10, mo = 1e9 + 9; 8 int n, m, a[N], f[N], suf[N], sua[N], que[N][2], tot, siz, d[N]; 9 10 void init() { 11 f[1] = f[2] = 1; 12 for (int i = 3; i <= n; i ++) f[i] = (f[i - 1] + f[i - 2]) % mo; 13 for (int i = 1; i <= n; i ++) suf[i] = (suf[i - 1] + f[i]) % mo; 14 } 15 16 void rebuild() { 17 memset(d, 0, sizeof d); 18 for (int i = 1; i <= tot; i ++) { 19 int l = que[i][0], r = que[i][1]; 20 (d[l] += 1) %= mo; 21 (d[r + 1] += mo - f[r - l + 2]) %= mo; 22 (d[r + 2] += mo - f[r - l + 1]) %= mo; 23 } 24 for (int i = 1; i <= n; i ++) (d[i] += (d[i - 1] + d[i - 2]) % mo) %= mo, (a[i] += d[i]) %= mo, sua[i] = (sua[i - 1] + a[i]) % mo; 25 tot = 0; 26 } 27 28 void query(int l, int r) { 29 int ans = (sua[r] - sua[l - 1] + mo) % mo; 30 for (int i = 1; i <= tot; i ++) { 31 int x = que[i][0], y = que[i][1]; 32 if (r < x || l > y) continue; 33 (ans += (suf[min(y, r) - x + 1] - suf[max(x, l) - x] + mo) % mo) %= mo; 34 } 35 printf("%d\n", ans); 36 } 37 38 int main() { 39 scanf("%d %d", &n, &m); 40 init(); 41 siz = sqrt(m); 42 for (int i = 1; i <= n; i ++) scanf("%d", &a[i]), sua[i] = (sua[i - 1] + a[i]) % mo; 43 while (m --) { 44 int p, l, r; 45 scanf("%d %d %d", &p, &l, &r); 46 if (p == 1) { 47 que[++ tot][0] = l, que[tot][1] = r; 48 if (tot == siz) rebuild(); 49 } else query(l, r); 50 } 51 return 0; 52 }
标签:
原文地址:http://www.cnblogs.com/awner/p/5796977.html