[CF446C] DZY Loves Fibonacci Numbers - 二次剩余,线段树维护等比数列

Description

在本题中,我们用 \(f_i\) 来表示第 \(i\) 个斐波那契数。维护一个序列 \(a\),长度为 \(n\),有 \(m\) 次操作:

  1. 1 l r:对于 \(l\le i\le r\),将 \(a_i\) 加上 \(f_{i-l+1}\)
  2. 2 l r:求 \(\displaystyle\left(\sum_{i=l}^ra_i\right)\bmod(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('\n');
        }
    }
}

相关文章: