[CF633H] Fibonacci-ish II
多个区间和去重交给莫队。
用线段树维护 \(\begin{bmatrix} fib_{i-1} \times val, fib_i \times val \end{bmatrix}\)。
具体和线段树的区间和差不多,上传时左右儿子矩阵相加,下传时左右儿子矩阵都乘上懒标记。
斐波那契数列下一项的矩阵是 \(\begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}\),插入新数时区间乘这个矩阵就行。
区间除要用刚才矩阵的逆矩阵 \(\begin{bmatrix} -1 & 1 \\ 1 & 0 \end{bmatrix}\),现在就变成乘法了。
卡常小技巧:
用 unsigned short,矩阵乘法展开,离散化。
#include <bits/stdc++.h>
#define int unsigned short
#define ls p << 1
#define rs p << 1 | 1
#define Ad tr[p].ad
#define mid (l + r >> 1)
using namespace std;
inline signed read()
{
    signed f = 0, ans = 0;
    char c = getchar();
    while (!isdigit(c))
        f |= c == '-', c = getchar();
    while (isdigit(c))
        ans = (ans << 3) + (ans << 1) + c - 48, c = getchar();
    return f ? -ans : ans;
}
void write(int x)
{
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
const signed N = 3e4 + 5, M = N << 2;
signed a[N], b[N];
int n, m, sq, si, mod;
int fib[N], res[N], mp[N], id[N];
struct que
{
    int l, r, id;
    bool operator<(const que &x) const
    {
        if (l / sq != x.l / sq)
            return l < x.l;
        return l / sq & 1 ? r < x.r : r > x.r;
    }
} q[N];
template <typename T>
inline T Mod(T &&x) { return x >= mod ? x -= mod : x; }
struct Matrix
{
    int h, w, a[2][2];
    Matrix() : Matrix(1, 2) {}
    Matrix(int H, int W) : h(H), w(W)
    {
        for (int i = 0; i < h; ++i)
            for (int j = 0; j < w; ++j)
                a[i][j] = 0;
    }
    Matrix(short id)
    {
        if (id == 0)
            assert(0);
        else
        {
            h = w = 2;
            if (id > 0)
                a[0][1] = a[1][0] = a[1][1] = 1, a[0][0] = 0;
            else
                a[1][0] = a[0][1] = 1, a[0][0] = mod - 1, a[1][1] = 0;
        }
    }
    Matrix operator+(const Matrix &rhs) const
    {
        Matrix ans(*this);
        Mod(ans.a[0][0] += rhs.a[0][0]);
        Mod(ans.a[0][1] += rhs.a[0][1]);
        return ans;
    }
    Matrix operator*(const Matrix &rhs) const
    {
        Matrix ans(h, rhs.w);
        if (h == 1 && w == 2)
        {
            ans.a[0][0] = Mod(1 * a[0][0] * rhs.a[0][0] % mod + 1 * a[0][1] * rhs.a[1][0] % mod);
            ans.a[0][1] = Mod(1 * a[0][0] * rhs.a[0][1] % mod + 1 * a[0][1] * rhs.a[1][1] % mod);
        }
        else
        {
            ans.a[0][0] = Mod(1 * a[0][0] * rhs.a[0][0] % mod + 1 * a[0][1] * rhs.a[1][0] % mod);
            ans.a[0][1] = Mod(1 * a[0][0] * rhs.a[0][1] % mod + 1 * a[0][1] * rhs.a[1][1] % mod);
            ans.a[1][0] = Mod(1 * a[1][0] * rhs.a[0][0] % mod + 1 * a[1][1] * rhs.a[1][0] % mod);
            ans.a[1][1] = Mod(1 * a[1][0] * rhs.a[0][1] % mod + 1 * a[1][1] * rhs.a[1][1] % mod);
        }
        return ans;
    }
} u[N], ru[N];
struct Tree
{
    struct tree
    {
        Matrix v;
        int sum;
        short ad;
    } tr[M];
    void down(signed p)
    {
        if (Ad > 0)
        {
            tr[ls].v = tr[ls].v * u[Ad], tr[ls].ad += Ad;
            tr[rs].v = tr[rs].v * u[Ad], tr[rs].ad += Ad;
            Ad = 0;
        }
        else if (Ad < 0)
        {
            tr[ls].v = tr[ls].v * ru[-Ad], tr[ls].ad += Ad;
            tr[rs].v = tr[rs].v * ru[-Ad], tr[rs].ad += Ad;
            Ad = 0;
        }
    }
    void update(int p) { tr[p].v = tr[ls].v + tr[rs].v; }
    void insert(int l, int r, int x, signed p, int rk)
    {
        ++tr[p].sum;
        if (l == r)
        {
            tr[p].v = Matrix(1, 2);
            tr[p].v.a[0][0] = 1 * fib[rk - 1] * b[x] % mod;
            tr[p].v.a[0][1] = 1 * fib[rk] * b[x] % mod;
            return;
        }
        down(p);
        if (mid >= x)
            insert(l, mid, x, ls, rk);
        else
            insert(mid + 1, r, x, rs, rk);
        update(p);
    }
    void insert(int x, int rk) { insert(1, si, x, 1, rk); }
    void remove(int l, int r, int x, signed p)
    {
        --tr[p].sum;
        if (l == r)
        {
            tr[p].v = Matrix();
            return;
        }
        down(p);
        if (mid >= x)
            remove(l, mid, x, ls);
        else
            remove(mid + 1, r, x, rs);
        update(p);
    }
    void remove(int x) { remove(1, si, x, 1); }
    void multiply(int l, int r, int s, int t, signed p, Matrix &v, short w)
    {
        if (l >= s && r <= t)
        {
            tr[p].v = tr[p].v * v, tr[p].ad += w;
            return;
        }
        down(p);
        if (mid >= s)
            multiply(l, mid, s, t, ls, v, w);
        if (mid < t)
            multiply(mid + 1, r, s, t, rs, v, w);
        update(p);
    }
    void multiply(int s, int t, Matrix &v, short w) { multiply(1, si, s, t, 1, v, w); }
    int ask_ans() { return tr[1].v.a[0][1]; }
    int rank(int l, int r, int s, int t, signed p)
    {
        if (l >= s && r <= t)
            return tr[p].sum;
        down(p);
        int ans = 0;
        if (mid >= s)
            ans = rank(l, mid, s, t, ls);
        if (mid < t)
            ans += rank(mid + 1, r, s, t, rs);
        return ans;
    }
    int rank(int x) { return rank(1, si, 1, x, 1); }
} tr;
inline void insert(int i)
{
    if (++mp[id[i]] == 1)
    {
        tr.insert(id[i], tr.rank(id[i]) + 1);
        tr.multiply(id[i] + 1, n, u[1], 1);
    }
}
inline void remove(int i)
{
    if (--mp[id[i]] == 0)
    {
        tr.remove(id[i]);
        tr.multiply(id[i] + 1, n, ru[1], -1);
    }
}
signed main()
{
    // freopen("chk.in", "r", stdin);
    // freopen("chk.out", "w", stdout);
    n = read(), sq = sqrt(n);
    mod = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read();
    copy(a + 1, a + n + 1, b + 1);
    sort(b + 1, b + n + 1);
    si = unique(b + 1, b + n + 1) - b;
    for (int i = 1; i <= n; ++i)
        id[i] = lower_bound(b + 1, b + si, a[i]) - b;
    for (int i = 1; i <= n; ++i)
        b[i] = b[i] % mod;
    fib[1] = fib[2] = 1;
    for (int i = 3; i <= n; ++i)
        fib[i] = Mod(fib[i - 1] + fib[i - 2]);
    u[1] = Matrix(1), ru[1] = Matrix(-1);
    for (int i = 2; i <= n; ++i)
        u[i] = u[i - 1] * u[1], ru[i] = ru[i - 1] * ru[1];
    m = read();
    for (int i = 1; i <= m; ++i)
        q[i].l = read(), q[i].r = read(), q[i].id = i;
    sort(q + 1, q + m + 1);
    int l = 1, r = 0;
    for (int i = 1; i <= m; ++i)
    {
        while (l > q[i].l)
            insert(--l);
        while (r < q[i].r)
            insert(++r);
        while (l < q[i].l)
            remove(l++);
        while (r > q[i].r)
            remove(r--);
        res[q[i].id] = tr.ask_ans();
    }
    for (int i = 1; i <= m; ++i)
        write(res[i]), putchar('\n');
    return 0;
}
 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号