SP19543 GSS8 - Can you answer these queries VIII 题解

插入删除区间查询,考虑直接在平衡树上维护答案。

设 $u$ 的左子树为 $L$,右子树为 $R$,$u$ 点的权值为 $v$,则对于一个 $k$,$u$ 子树的答案为

$$ \begin{aligned} &\sum a_i\times i^k\\ =&v\times(|L|+1)^k+\sum_L a_i\times i^k+\sum_R a_i\times(|L|+1+i)^k\\ =&v\times(|L|+1)^k+\sum_L a_i\times i^k+\sum_R a_i\sum_{j=0}^k{k\choose j}i^j(|L|+1)^{k-j}\\ =&v\times(|L|+1)^k+\sum_L a_i\times i^k+\sum_{j=0}^k{k\choose j}(|L|+1)^{k-j}\sum_R a_i\times i^j\\ \end{aligned} $$

这样就可以直接合并两棵子树的答案了。

#include <cstdio>
#include <cstdlib>
#define int unsigned
char o;
int n, m, C[15][15], p[300050][15];
struct T
{
    T *l, *r;
    int v, q[11], k, s;
    T(int _) : l(0), r(0), v(_), k(rand()), s(1)
    {
        for (int i = 0; i <= 10; ++i)
            q[i] = _;
    }
    void u()
    {
        s = 1;
        if (l)
            s += l->s;
        if (r)
            s += r->s;
        int z = l ? l->s : 0;
        for (int i = 0; i <= 10; ++i)
        {
            q[i] = v * p[z + 1][i];
            if (l)
                q[i] += l->q[i];
            if (r)
                for (int j = 0; j <= i; ++j)
                    q[i] += C[i][j] * p[z + 1][i - j] * r->q[j];
        }
    }
} *r, *a, *b, *c;
void S(T *x, int k, T *&a, T *&b)
{
    if (!x)
        return void(a = b = 0);
    int z = x->l ? x->l->s : 0;
    if (z >= k)
        b = x, S(x->l, k, a, b->l), b->u();
    else
        a = x, S(x->r, k - z - 1, a->r, b), a->u();
}
T *M(T *a, T *b)
{
    if (!a)
        return b;
    if (!b)
        return a;
    if (a->k < b->k)
        return a->r = M(a->r, b), a->u(), a;
    else
        return b->l = M(a, b->l), b->u(), b;
}
signed main()
{
    C[0][0] = 1;
    for (int i = 1; i <= 10; ++i)
    {
        C[i][0] = 1;
        for (int j = 1; j <= i; ++j)
            C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
    }
    for (int i = 0; i <= 3e5; ++i)
        for (int j = p[i][0] = 1; j <= 10; ++j)
            p[i][j] = p[i][j - 1] * i;
    scanf("%u", &n);
    for (int i = 1, x; i <= n; ++i)
        scanf("%u", &x), r = M(r, new T(x));
    scanf("%u", &m);
    for (int i = 0, x, y, k; i < m; ++i)
    {
        scanf(" %c%u", &o, &x);
        switch (o)
        {
        case 'I':
            scanf("%u", &y);
            S(r, x, a, b);
            r = M(a, M(new T(y), b));
            break;
        case 'D':
            S(r, x, a, b);
            S(b, 1, b, c);
            r = M(a, c);
            break;
        case 'R':
            scanf("%u", &y);
            S(r, x, a, b);
            S(b, 1, b, c);
            r = M(a, M(new T(y), c));
            break;
        case 'Q':
            scanf("%u%u", &y, &k);
            S(r, y + 1, a, c);
            S(a, x, a, b);
            printf("%u\n", b->q[k]);
            r = M(a, M(b, c));
            break;
        }
    }
    return 0;
}
posted @ 2023-12-18 16:13  5k_sync_closer  阅读(2)  评论(0编辑  收藏  举报  来源