斐波納契數列 線段樹的維護

2021-06-16 22:50:55 字數 3746 閱讀 6412

像一般的數列維護一樣,這題也差不多。有乙個數列a,修改操作是將a[i] .. a[j]的值都加上乙個d,詢問操作就有點不同,給出i和j,求出a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i)模上乙個數的結果。其中fib就是斐波納契數列,即fib(0) = fib(1) = 1,對於fib(i)(> 1), fib(i) = fib(i -1) + fib(i - 2)。

已知a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i)或者儲存多一些需要的資訊,怎樣求出a[i] * fib(0+ k) + a[i + 1] * fib(1+ k) + a[i + 2] * fib(2+ k) + ... + a[j] * fib(j - i+ k)。

斐波納契數列有乙個奇特的性質,嘗試如下的運算,得出的序列還是斐波納契數列。

a  1  1  2  3  5  8  13  ....

b  1  2  3  5  8  13  21 ....

將同乙個位置的相加(c[i] = a[i] + b[i]),得:

c  2  3  5  8  13  21  34 ....

再加加d[i] = b[i] + c[i],得:

d 3  5  8  13  21  34  55

如此看來,我們可以設:

x =  a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i);

y =  a[i] * fib(1) + a[i + 1] * fib(2) + a[i + 2] * fib(3) + ... + a[j] * fib(j - i + 1);

那麼:x + y  = a[i] * fib(2) + a[i + 1] * fib(3) + a[i + 2] * fib(4) + ... + a[j] * fib(j - i + 2);

x + 2y = a[i] * fib(3) + a[i + 1] * fib(4) + a[i + 2] * fib(5) + ... + a[j] * fib(j - i + 3);

2x + 3y = a[i] * fib(4) + a[i + 1] * fib(5) + a[i + 2] * fib(6) + ... + a[j] * fib(j - i + 4);

3x + 5y = a[i] * fib(5) + a[i + 1] * fib(6) + a[i + 2] * fib(7) + ... + a[j] * fib(j - i + 5);

fib(k - 2) * x + fib(k - 1) * y = a[i] * fib(0+ k) + a[i + 1] * fib(1+ k) + a[i + 2] * fib(2+ k) + ... + a[j] * fib(j - i+ k)   (k > 1),k = 0,k = 1的情況額外處理,fib數列預處理。

這樣,我們就可以實現維護了,需要儲存兩個資訊,就是上述的x,y。接著就是資訊傳遞的操作,也就是整段都加上d。

也就是已知a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i),求(a[i]+ d) * fib(0) + (a[i + 1]+ d) * fib(1) + (a[i + 2]+ d) * fib(2) + ... + (a[j]+ d) * fib(j - i)。

通過拆分得:a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i) +d * fib(0) + d * fib(1) + d * fib(2) + ... + d * fib(j - i)

a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i) +d * (fib(0) + fib(1) + fib(2) + ... + fib(j - i))

fib的數列和有個定理:fib(0) + fib(1) + fib(2) + ... + fib(i) = fib(i + 2) - 1。這樣又可以實現資訊傳遞的操作了。問題到此就解決了。此外,我們可以從fib的矩陣乘法中聯想到合併資訊的方法,本質是一樣的。

對於一些比較難維護的資料,可以通過列公式等方法找出其中的規律,哪怕沒有什麼規律,我們也能從中得到一些啟發。還可以想想另一些方法,即使它們看起來是不能解決問題的。

#include #include using namespace std;

typedef long long ll;

typedef pairpii;

const ll mod = 1000000000ll;

const int n = 200007;

int n, m;

ll fib[n], x[n], y[n];

int nnode = 1;

struct node

inline int size()

}node[n << 1], *root = &node[0];

inline pii calc(pii a, int k)

pii operator + (pii const &a, pii const &b)

void build(node *p, int le, int ri)

else }

void update(node *p, ll flag)

void modify(node *p, int le, int ri, ll delta)

int mi = p -> mi();

if (le < mi) modify(p -> lch, le, ri, delta);

if (ri > mi) modify(p -> rch, le, ri, delta);

p -> dat = p -> lch -> dat +

calc(p -> rch -> dat, p -> lch -> size()); }}

pii ask(node *p, int le, int ri)

int mi = p -> mi();

if (le < mi && ri > mi)

return ask(p -> lch, le, ri) +

calc(ask(p -> rch, le, ri),

p -> lch -> hi - max(le, p -> lch -> lo));

else if (le < mi) return ask(p -> lch, le, ri);

else return ask(p -> rch, le, ri);

}void init()

void solve()

else

}}int main()

斐波納契數列

f 1 0 f 2 1 f n f n 1 f n 2 斐波納契數列決定審美和諧性 800年前,義大利的數學家李奧納多 斐波那契出版了驚世之作 算盤書 在 算盤書 裡,斐波納契提出了著名的 兔子生兔子的問題 有乙個人把一對兔 子放在四面圍著的地方。假定每個月一對兔子生下另外一對。而這新的一對在二個月...

斐波納契數列

斐波納契數列又稱 分割數列 因數學家列昂納多 斐波那契 leonardoda fibonacci 以兔子繁殖為例子而引入,故又稱為 兔子數列 指的是這樣乙個數列 1 1 2 3 5 8 13 21 34 此本章通過多種方式實現斐波納契數列 第一種 for 迴圈實現 a,b 0,1 for i in ...

python斐波納契數列

fibonacci series 斐波納契數列 兩個元素的總和確定了下乙個數 a,b 0,1 while b 10 print b a,b b,a b fibonacci series 斐波納契數列 兩個元素的總和確定了下乙個數 a,b 0,1 while b 1000 if a b 1000 pr...