题解 平方和

题目描述

给出一个 N 个整数构成的序列,有 M 次操作,每次操作有一下三种:
①Insert Y X,在序列的第 Y 个数之前插入一个数 X;
②Add L R X,对序列中第 L 个数到第 R 个数,每个数都加上 X;
③Query L R,询问序列中第 L 个数到第 R 个数的平方和。

输入格式

第一行一个正整数 N,表示初始序列长度。
第二行 N 个整数 Ai,表示初始序列中的数。
第三行一个正整数 M,表示操作数。
接下来 M 行,每行一种操作。

输出格式

对于每一个 Query 操作输出答案。由于答案可能很大,请 mod 7459 后输出。

数据范围

100%的数据满足 \(N≤10^5,M≤10^5\),且 Add 和 Insert 操作中\(|X|≤1000,|A_i|≤1000\)

解题思路

考场第一题就是这道数据结构,写了160+行代码喜提0分,然后改错从160行->270行,这不写篇题解庆祝一下。

显然,如果没有操作一,就是一道线段树水题,但是这个操作一就很烦,但这个题很良心,直接线段树做可以有50分。对于操作一,加入一个数并不会改变之前的数的相对位置,所以可以这样处理,先求出所有操作一后的序列,用这个序列来建立一个线段树,对于每一次修改操作,就相当于一次单点修改。剩下的直接线段树就完了。

那么问题来了,如何求出这个最终的序列,插入一个数,似乎可以链表,但是很显然,链表在这道题中需要 \(O(n^2)\)
插入,这就和暴力没啥区别了。可以用 Splay 来维护,考场上为了偷懒直接用了平板电视,结果假了。所以还是老老实实粘了个 Splay 的板子上去,然后嘛,每次操作一直接在 Splay 中插入就行了,这样就可以求出每一次修改在线段树中的下标位置了。对于操作二和三,就可以直接用平板电视中的平衡数维护区间第 L 个数与第 R 个数了。
时间复杂度 \(O(nlogn)\)。然而 std 只有 100+行。

上面的做法纯属sb做法,直接Splay在线维护就行,当时脑抽了还加了个线段树。

代码

#include<iostream>
#include<unordered_map>
#include<cstdio>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include<ctime>
using namespace __gnu_pbds;
using namespace std;
const int N = 1e5 + 5;
const int MOD = 7459;
const int INF = 0x3f3f3f3f;
typedef long long ll;

ll id[2 * N], a[N], b[2 * N], n, m, tot;
struct query
{
    char opt[11];
    ll x, y, z;
} q[N];
struct Tree
{
    ll l, r, sum1, sum2, lz, len;
} tr[8 * N];
struct Splay
{
    struct tr
    {
        ll s[2], p, v, siz;
    } tree[8 * N];
    ll root, idx, cnt;

    void pushup(ll p)
    {
        tree[p].siz = tree[tree[p].s[0]].siz + tree[tree[p].s[1]].siz + 1;
    }

    void rotate(ll x)
    {
        ll y = tree[x].p, z = tree[y].p;
        ll k = tree[y].s[1] == x;
        tree[z].s[tree[z].s[1] == y] = x, tree[x].p = z;
        tree[y].s[k] = tree[x].s[k ^ 1], tree[tree[x].s[k ^ 1]].p = y;
        tree[x].s[k ^ 1] = y, tree[y].p = x;
        pushup(y), pushup(x);
    }

    void splay(ll x, ll k)
    {
        while (tree[x].p != k)
        {
            ll y = tree[x].p, z = tree[y].p;
            if (z != k)
            {
                if ((tree[y].s[1] == x) ^ (tree[z].s[1] == y))
                    rotate(x);
                else
                    rotate(y);
            }
            rotate(x);
        }
        if (!k)
            root = x;
    }

    void insert(ll v)
    {
        ll u = root, p = 0;
        while (u)
            p = u, u = tree[u].s[v > tree[u].v];
        u = ++idx;
        if (p)
            tree[p].s[v > tree[p].v] = u;
        tree[u].v = v, tree[u].siz = 1, tree[u].p = p;
        splay(u, 0);
    }

    ll getk(ll k)
    {
        ll u = root;
        while (2333)
        {
            if (tree[tree[u].s[0]].siz >= k)
                u = tree[u].s[0];
            else if (tree[tree[u].s[0]].siz + 1 == k)
                return u;
            else
                k -= tree[tree[u].s[0]].siz + 1, u = tree[u].s[1];
        }
        return -1;
    }

    void dfs(int now)
    {
        if(tree[now].s[0])
            dfs(tree[now].s[0]);
        if (tree[now].v >= 1 && tree[now].v <= 2 * n)
            b[++cnt] = tree[now].v;
        if(tree[now].s[1])
            dfs(tree[now].s[1]);
    }

} t;
tree<ll, null_type, less<ll>, rb_tree_tag, tree_order_statistics_node_update> s;
unordered_map<ll, ll> pos;

ll read()
{
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 3) + (x << 1) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}

void pushup(ll p)
{
    tr[p].sum1 = (tr[p << 1].sum1 + tr[p << 1 | 1].sum1) % MOD;
    tr[p].sum2 = (tr[p << 1].sum2 + tr[p << 1 | 1].sum2) % MOD;
    tr[p].len = tr[p << 1].len + tr[p << 1 | 1].len;
}

void pushdown(ll p)
{
    Tree &w = tr[p], &l = tr[p << 1], &r = tr[p << 1 | 1];
    ll x = w.lz, xx = w.lz * w.lz % MOD;
    l.sum2 = (l.sum2 + 2 * x * l.sum1 + xx * l.len) % MOD;
    l.sum1 = (l.sum1 + l.len * x) % MOD;
    l.lz = (l.lz + w.lz) % MOD;
    r.sum2 = (r.sum2 + 2 * x * r.sum1 + xx * r.len) % MOD;
    r.sum1 = (r.sum1 + r.len * x) % MOD;
    r.lz = (r.lz + w.lz) % MOD;
    w.lz = 0;
}

void build(ll l, ll r, ll p)
{
    tr[p].l = l, tr[p].r = r;
    if (l == r)
    {       
        if (b[l] <= n)
        {
            tr[p].len = 1;
            tr[p].sum1 = a[b[l]] % MOD;
            tr[p].sum2 = a[b[l]] * a[b[l]] % MOD;
            s.insert(l);
        }
        else
            id[b[l]] = l;
        return;
    }
    ll mid = (l + r) >> 1;
    build(l, mid, p << 1);
    build(mid + 1, r, p << 1 | 1);
    pushup(p);
}

void modify(ll p, ll k, ll x)
{
    if (tr[p].l == tr[p].r)
    {
        tr[p].len = 1;
        tr[p].sum1 = x % MOD;
        tr[p].sum2 = x * x % MOD;
        return;
    }
    pushdown(p);
    ll mid = (tr[p].l + tr[p].r) >> 1;
    if (k <= mid)
        modify(p << 1, k, x);
    else
        modify(p << 1 | 1, k, x);
    pushup(p);
}

void update(ll p, ll l, ll r, ll x)
{
    if (tr[p].l >= l && tr[p].r <= r)
    {
        tr[p].sum2 = (tr[p].sum2 + tr[p].sum1 * 2 * x + x * x * tr[p].len) % MOD;
        tr[p].sum1 = (tr[p].len * x + tr[p].sum1) % MOD;
        tr[p].lz = (tr[p].lz + x) % MOD;
        return;
    }
    pushdown(p);
    ll mid = (tr[p].l + tr[p].r) >> 1;
    if (l <= mid)
        update(p << 1, l, r, x);
    if (r > mid)
        update(p << 1 | 1, l, r, x);
    pushup(p);
}

ll query(ll p, ll l, ll r)
{
    if (tr[p].l >= l && tr[p].r <= r)
        return tr[p].sum2;
    pushdown(p);
    ll mid = (tr[p].l + tr[p].r) >> 1, res = 0;
    if (l <= mid)
        res = (res + query(p << 1, l, r)) % MOD;
    if (r > mid)
        res = (res + query(p << 1 | 1, l, r)) % MOD;
    return res;
}

int main()
{
    n = read();
    ll cnt = n;
    t.insert(-INF), t.insert(INF);
    for (ll i = 1; i <= n; i++)
    {
        a[i] = read();
        t.insert(i);
    }
    m = read();
    ll tot =0;
    for (ll i = 1; i <= m; i++)
    {
        scanf("%s", q[i].opt);
        if (q[i].opt[0] == 'I')
        {
            q[i].x = read(), q[i].y = read();
            ll x = t.getk(q[i].x), y = t.getk(q[i].x + 1);
            t.splay(x, 0), t.splay(y, x);
            t.tree[y].s[0] = ++t.idx;
            t.tree[t.idx].p = y, cnt++;
            t.tree[t.idx].v = n + (++tot), t.tree[t.idx].siz = 1;
            t.pushup(y), t.pushup(x);
            t.splay(t.idx, 0);
        }
        else if (q[i].opt[0] == 'A')
            q[i].x = read(), q[i].y = read(), q[i].z = read();
        else
            q[i].x = read(), q[i].y = read();
    }
    t.dfs(t.root);
    build(1, cnt, 1);
    tot = 0;
    for (ll i = 1; i <= m; i++)
    {
        if (q[i].opt[0] == 'I')
        {
            s.insert(id[n + (++tot)]);
            modify(1, id[n + tot], q[i].y);            
        }
        else if (q[i].opt[0] == 'A')
        {
            ll l = *s.find_by_order(q[i].x - 1);
            ll r = *s.find_by_order(q[i].y - 1);   
            update(1, l, r, q[i].z);            
        }
        else
        {
            ll l = *s.find_by_order(q[i].x - 1);
            ll r = *s.find_by_order(q[i].y - 1);
            printf("%lld\n", (query(1, l, r) % MOD + MOD) % MOD);
        }
    }
    return 0;
}
posted @ 2021-11-12 09:03  DSHUAIB  阅读(36)  评论(0编辑  收藏  举报