CF633H Fibonacci-ish II 题解

莫队,考虑加入、删除的贡献。

需要维护若干二元组 $(a_i,b_i)$,支持 $a_i$ 单点修改,$b_i$ 区间加减 $1$,求全局 $\sum a_if_{b_i}$,其中 $f$ 是斐波那契数列,

维护 $B_i=\begin{bmatrix}f_{b_i}&f_{b_i-1}\end{bmatrix}$,则问题变为 $a_i$ 单点修改,$B_i$ 区间乘除 $\begin{bmatrix}1&1\\1&0\end{bmatrix}$,求全局 $\sum a_iB_i$,

线段树维护之。卡一卡常。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define K 200
using namespace std;
struct Q
{
    int l, r, i;
} q[30050];
int n, m, z, M, a[30050], _a[30050], b[30050], c[30050], v[30050], Z[30050];
bool O(Q x, Q y) { return b[x.l] == b[y.l] ? b[x.l] & 1 ? x.r < y.r : x.r > y.r : x.l < y.l; }
struct S
{
    int a[2][2];
    S() { memset(a, 0, sizeof a); }
    S operator+(S b)
    {
        S c;
        for (int i = 0; i < 2; ++i)
            for (int j = 0; j < 2; ++j)
                c.a[i][j] = (a[i][j] + b.a[i][j]) % M;
        return c;
    }
    S operator*(S b)
    {
        S c;
        for (int i = 0; i < 2; ++i)
            for (int j = 0; j < 2; ++j)
            {
                int q = 0;
                for (int k = 0; k < 2; ++k)
                    q += a[i][k] * b.a[k][j];
                c.a[i][j] = q % M;
            }
        return c;
    }
    S operator*(long long k)
    {
        S c;
        for (int i = 0; i < 2; ++i)
            for (int j = 0; j < 2; ++j)
                c.a[i][j] = a[i][j] * k % M;
        return c;
    }
} B, F, _F, G[30050], _G[30050];
struct T
{
    S q;
    int s, z;
} R[30050 << 2];
void u(int p) { R[p].q = R[p << 1].q + R[p << 1 | 1].q; }
void f(int p, int s, int t, int x)
{
    if (x >= 0)
        R[p].q = R[p].q * G[x];
    else
        R[p].q = R[p].q * _G[-x];
    R[p].z += x;
    R[p].s += x;
}
void d(int p, int s, int t)
{
    int m = s + t >> 1;
    if (R[p].z)
        f(p << 1, s, m, R[p].z), f(p << 1 | 1, m + 1, t, R[p].z), R[p].z = 0;
}
void T(int l, int r, int x, int s, int t, int p)
{
    if (l <= s && t <= r)
        return f(p, s, t, x);
    d(p, s, t);
    int m = s + t >> 1;
    if (l <= m)
        T(l, r, x, s, m, p << 1);
    if (r > m)
        T(l, r, x, m + 1, t, p << 1 | 1);
    u(p);
}
void C(int l, int x, int s, int t, int p)
{
    if (s == t)
    {
        R[p].q = B * G[R[p].s] * x;
        return;
    }
    d(p, s, t);
    int m = s + t >> 1;
    if (l <= m)
        C(l, x, s, m, p << 1);
    else
        C(l, x, m + 1, t, p << 1 | 1);
    u(p);
}
void I(int x, int u)
{
    if (!c[u]++)
    {
        C(u, x, 1, z, 1);
        if (u != z)
            T(u + 1, z, 1, 1, z, 1);
    }
}
void D(int x, int u)
{
    if (!--c[u])
    {
        C(u, 0, 1, z, 1);
        if (u != z)
            T(u + 1, z, -1, 1, z, 1);
    }
}
int main()
{
    F.a[0][0] = F.a[0][1] = F.a[1][0] = _F.a[0][1] = _F.a[1][0] = B.a[0][0] = G[0].a[0][0] = G[0].a[1][1] = 1;
    _G[0] = G[0];
    scanf("%d%d", &n, &M);
    _F.a[1][1] = M - 1;
    for (int i = 1; i <= 3e4; ++i)
        G[i] = G[i - 1] * F, _G[i] = _G[i - 1] * _F;
    for (int i = 1; i <= n; ++i)
        scanf("%d", a + i), b[i] = (i - 1) / K + 1, v[z++] = a[i];
    sort(v, v + z);
    z = unique(v, v + z) - v;
    for (int i = 1; i <= n; ++i)
        _a[i] = lower_bound(v, v + z, a[i]) - v + 1;
    scanf("%d", &m);
    for (int i = 0; i < m; ++i)
        scanf("%d%d", &q[i].l, &q[i].r), q[i].i = i;
    sort(q, q + m, O);
    for (int i = 0, l = 1, r = 0; i < m; ++i)
    {
        while (l > q[i].l)
            --l, I(a[l], _a[l]);
        while (r < q[i].r)
            ++r, I(a[r], _a[r]);
        while (l < q[i].l)
            D(a[l], _a[l]), ++l;
        while (r > q[i].r)
            D(a[r], _a[r]), --r;
        Z[q[i].i] = R[1].q.a[0][0];
    }
    for (int i = 0; i < m; ++i)
        printf("%d\n", Z[i]);
    return 0;
}
posted @ 2023-12-07 16:16  5k_sync_closer  阅读(1)  评论(0编辑  收藏  举报  来源