cf447E DZY Loves Fibonacci Numbers

传送门
这题是真的牛

  • 区间加操作,使得区间的值加上对应的斐波那契数列。
  • 区间查询操作,求区间和

其实这有个规律,看见斐波那契数列和(mod)(1e9 + 9),就知道要用二次剩余来搞了,因为斐波那契的通项公式(sqrt{5})在模(1e9 + 9)下是有二次剩余的。

根据二次剩余,斐波那契的另一个表达式为

[F_n equiv 276601605(691504013^n-308495997^n) space (modspace 1e9+9) ]

那么就可以把这题转换为用线段树维护一下等比数列了。但是注意的是,这题是有两个等比数列,因为等比数列加等比数列不一定是等比数列,除非(q)相同。
那么维护两个等比数列,线段树里构建两个值用于维护当前的左区间的首项值,两个区间的公比是不同的。

注意的时,在每次修改都需要注意首项的值,因为操作里面首项(a_1)是对于给出的左区间而言的,所以对于每个线段区间,都需要处理好当前左区间的首项值。而且,在pushdown时也需要注意变化右孩子的首项值。

考虑到在线段树里面用快速幂会乘上一个(logn)的时间复杂度,所以就先预处理下两个公比的幂次方,等比数列求和时分母的逆元的值。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const int N = 3e5 + 5;
const int mod = 1e9 + 9;
const int q1 = 691504013, q2 = 308495997;
const int aa1 = 138300803, aa2 = 861699207;
const int inv1 = 691504013, inv2 = 308495997;
ll mul1[N] = {1}, mul2[N] = {1};
void ex_gcd(ll a, ll b, ll &d, ll &x, ll &y){
    if(!b) {
        d = a, x = 1, y = 0;
        return;
    }
    ex_gcd(b, a % b, d, y, x);
    y -= x * (a / b);
}
ll inv(ll a, ll p){//求a在p模下的逆元
    ll d, x, y;
    ex_gcd(a, p, d, x, y);
    return d == 1 ? (x % p + p) % p : -1;//d = 1时才有逆元
}
ll S(ll n, ll a1, ll q){
    if(q == q1) return (a1 * (mul1[n] - 1) % mod * inv1 % mod + mod) % mod;
    return (a1 * (mul2[n] - 1) % mod * inv2 % mod + mod) % mod;
}
struct SegTree{
    struct Node{
        int l, r;
        ll sum, a1, a2;
        #define l(p) tree[p].l
        #define r(p) tree[p].r
        #define sum(p) tree[p].sum
        #define a1(p) tree[p].a1
        #define a2(p) tree[p].a2
        #define lson (p << 1)
        #define rson (p << 1 | 1)
    } tree[N << 2];
    void pushup(int p){
        sum(p) = (sum(lson) + sum(rson) + mod) % mod;
    }
    void pushdown(int p) {
        if(a1(p)) {
            a1(lson) += a1(p); a1(lson) = (a1(lson) % mod + mod) % mod;
            a1(rson) += mul1[l(rson) - l(lson)] * a1(p) % mod; a1(rson) = (a1(rson) % mod + mod) % mod;
            sum(lson) += S(r(lson) - l(lson) + 1, a1(p), q1); sum(lson) = (sum(lson) % mod + mod) % mod;
            sum(rson) += S(r(rson) - l(rson) + 1, mul1[l(rson) - l(lson)] * a1(p) % mod, q1); sum(rson) = (sum(rson) % mod + mod) % mod;
            a1(p) = 0;
        }
        if(a2(p)) {
            a2(lson) += a2(p); a2(lson) = (a2(lson) % mod + mod) % mod;
            a2(rson) += mul2[l(rson) - l(lson)] * a2(p) % mod; a2(rson) = (a2(rson) % mod + mod) % mod;
            sum(lson) += S(r(lson) - l(lson) + 1, a2(p), q2); sum(lson) = (sum(lson) % mod + mod) % mod;
            sum(rson) += S(r(rson) - l(rson) + 1, mul2[l(rson) - l(lson)] * a2(p) % mod, q2); sum(rson) = (sum(rson) % mod + mod) % mod;
            a2(p) = 0;
        }
    }
    void build(int p, int l, int r){
        l(p) = l, r(p) = r;
        a1(p) = a2(p) = sum(p) = 0;
        if(l == r) return;
        int mid = (l + r) >> 1;
        build(lson, l, mid); build(rson, mid + 1, r);
        pushup(p);
    }
    void Change(int p, int l, int r, int c){//[l,r]
        if(l <= l(p) && r(p) <= r){
            if(c == q1) {
                ll shou = 1ll * aa1 * mul1[l(p) - l] % mod; shou = (shou + mod) % mod;
                a1(p) += shou, a1(p) = (a1(p) + mod) % mod; 
                sum(p) += S(r(p) - l(p) + 1, shou, q1), sum(p) = (sum(p) % mod + mod) % mod;
            } 
            if(c == q2) {
                ll shou = 1ll * aa2 * mul2[l(p) - l] % mod; shou = (shou + mod) % mod;
                a2(p) += shou, a1(p) = (a1(p) + mod) % mod; 
                sum(p) += S(r(p) - l(p) + 1, shou, q2), sum(p) = (sum(p) % mod + mod) % mod;
            }
            return;
        }
        pushdown(p);
        int mid = (l(p) + r(p)) >> 1;
        if(l <= mid) Change(lson, l, r, c);
        if(r > mid) Change(rson, l, r, c);
        pushup(p);
    }
    ll Query(int p, int l, int r) { // [l,r]区间查询
        if(l <= l(p) && r(p) <= r) {
            return (sum(p) % mod + mod) % mod;
        }
        pushdown(p);
        int mid = (l(p) + r(p)) >> 1;
        ll ans = 0;
        if(l <= mid) ans += Query(lson, l, r), ans = (ans % mod + mod) % mod;
        if(r > mid) ans += Query(rson, l, r), ans = (ans % mod + mod) % mod;
        return ans = (ans % mod + mod) % mod;;
    }
} seg;
namespace IO {
    template <typename T>
    inline void w(T x) { if (x > 9) w(x / 10); putchar(x % 10 + 48); }
    template <typename T>
    inline void write(T x, char c) { if(x < 0) putchar('-'), x = -x; w(x); putchar(c); }
    template <typename T>
    inline void read(T &x) {
        x = 0; T f = 1; char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
        for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
        x *= f;
    }
};
int n, m;
int a[N];
void subtask1(int l, int r){
    seg.Change(1, l, r, q1);
    seg.Change(1, l, r, q2);
}
void subtask2(int l, int r){
    ll ans = a[r] - a[l - 1];
    ans += seg.Query(1, l, r); ans = (ans % mod + mod) % mod;
    IO::write(ans, '
');
}
int main(){
    for(int i = 1; i <= N - 3; i++) {
        mul1[i] = 1ll * mul1[i - 1] * q1 % mod;
        mul2[i] = 1ll * mul2[i - 1] * q2 % mod;
    }
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) IO::read(a[i]), a[i] = (a[i] + a[i - 1]) % mod;
    seg.build(1, 1, n);
    for(int i = 1; i <= m; i++) {
        int op, l, r;
        IO::read(op), IO::read(l), IO::read(r);
        if(op == 1) subtask1(l, r);
        else subtask2(l, r);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Emcikem/p/14226493.html