1 条题解

  • 0
    @ 2025-8-24 22:40:59

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 251Sec
    祈祷着今后的你的人生,永远都有幸福的“魔法”相伴。

    搬运于2025-08-24 22:40:59,当前版本为作者最后更新于2023-07-28 17:52:59,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    思维难度不高,但是难写的一批。

    考虑一个环内的贡献,设环内的点为 1c1 \sim c,则贡献为:

    $$\sum_{i=1}^n F_i \left(\sum_{j=1}^{i-1}H_j(c-i+j)-\sum_{i=j+1}^c H_j(i-j)\right) $$

    简单推一下这个式子,就可以得到它等于:

    $$\sum_{i=1}^c F_i \sum_{j=1}^c jH_j-\sum_{i=1}^c iF_i \sum_{j=1}^c H_j+c\sum\limits_{i=1}^{c}\sum\limits_{j=1}^{i-1}F_iG_j $$

    我们可以尝试对一个环维护出 $\sum F_i,\sum iF_i, \sum H_j, \sum jH_j, \sum\limits_{i>j} F_iG_j$ 这些东西,就可以算答案了。可以发现这些东西作为区间信息是可以合并的:前面四个的合并比较显然,第五个东西可以参考 CDQ 分治的思想,即将左边和右边内部的贡献加起来再加上左边对右边的贡献。

    看一下操作:后面两种操作是平凡的单点修改,考虑第一种操作。手玩一下,发现如果操作的两个点属于同一个环,那么这个环会裂成两个;如果两个点不属于同一个环,那么环会合并在一起。分讨一下,可以得到,我们需要这样一个数据结构:

    • 支持单点修改。
    • 支持区间分裂合并。
    • 支持查询上面提到的那一堆东西。

    可以发现 FHQ Treap 完美满足这个条件,所以写一棵 FHQ Treap 维护即可。

    最后放上我写的史山。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int P = 1e9 + 7;
    mt19937 rnd(251251);
    namespace Treap {
        struct Node {
            int ls, rs;
            int siz, pri, prt;
            ll f, h, sf, sh, tf, th, fh;
            ll ans;
            Node() {}
            Node(ll _f, ll _h) {
                f = _f; h = _h;
                sf = tf = f;
                sh = th = h;
                siz = 1; pri = rnd();
            }
        } f[100005];
        int tcn;
        void Pushup(Node &s, const Node &ls, const Node &rs) {
            s.sf = (ls.sf + rs.sf + s.f) % P;
            s.sh = (ls.sh + rs.sh + s.h) % P;
            s.tf = (ls.tf + rs.tf + rs.sf * (ls.siz + 1) % P + s.f * (ls.siz + 1) % P) % P;
            s.th = (ls.th + rs.th + rs.sh * (ls.siz + 1) % P + s.h * (ls.siz + 1) % P) % P;
            s.fh = (ls.fh + rs.fh + s.h * rs.sf % P + s.f * ls.sh % P + ls.sh * rs.sf % P) % P;
            s.siz = ls.siz + rs.siz + 1;
            s.ans = (s.sf * s.th % P - s.sh * s.tf % P + s.siz * s.fh % P + P) % P;
        }
        int NewNode(ll f, ll h) {
            int p = ++tcn;
            Treap::f[p] = Node(f, h);
            return p;
        }
        void Split(int p, int rk, int &x, int &y) {
            if (!p) {
                x = y = 0;
                return;
            }
            if (f[f[p].ls].siz + 1 <= rk) {
                x = p;
                Split(f[p].rs, rk - f[f[p].ls].siz - 1, f[p].rs, y);
            } else {
                y = p;
                Split(f[p].ls, rk, x, f[p].ls);
            }
            f[f[p].ls].prt = f[f[p].rs].prt = p;
            f[p].prt = 0;
            Pushup(f[p], f[f[p].ls], f[f[p].rs]);
        }
        int Merge(int x, int y) {
            if (!x || !y) return x | y;
            if (f[x].pri >= f[y].pri) {
                f[x].rs = Merge(f[x].rs, y);
                Pushup(f[x], f[f[x].ls], f[f[x].rs]);
                f[f[x].ls].prt = f[f[x].rs].prt = x;
                f[x].prt = 0;
                return x;
            } else {
                f[y].ls = Merge(x, f[y].ls);
                Pushup(f[y], f[f[y].ls], f[f[y].rs]);
                f[f[y].ls].prt = f[f[y].rs].prt = y;
                f[y].prt = 0;
                return y;
            }
        }
        int Rank(int p) {
            int rk = f[f[p].ls].siz + 1;
            while (p) {
                if (p == f[f[p].prt].rs) rk += f[f[f[p].prt].ls].siz + 1;
                p = f[p].prt;
            }
            return rk;
        }
        void ModifyF(int p, int i, ll w) {
            int x = 0, y = 0, z = 0;
            Split(p, i, x, z);
            Split(x, i - 1, x, y);
            f[y].f = f[y].sf = f[y].tf = w;
            Merge(Merge(x, y), z);
        }
        void ModifyH(int p, int i, ll w) {
            int x = 0, y = 0, z = 0;
            Split(p, i, x, z);
            Split(x, i - 1, x, y);
            f[y].h = f[y].sh = f[y].th = w;
            Merge(Merge(x, y), z);
        }
        int Find(int u) {
            return f[u].prt ? Find(f[u].prt) : u;
        }
    }
    using namespace Treap;
    int n, m;
    ll ans;
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            ll f, h;
            scanf("%lld%lld", &h, &f);
            if (i == 1) NewNode(f, h);
            else Merge(Find(1), NewNode(f, h));
        }
        ans = f[Find(1)].ans;
        scanf("%d", &m);
        while (m--) {
            int op, p, q;
            scanf("%d%d%d", &op, &p, &q);
            if (op == 1) {
                int x = Find(p), y = Find(q);
                if (x == y) {
                    ans -= f[x].ans;
                    int rp = Rank(p), rq = Rank(q);
                    if (rp < rq) {
                        int a, b, c;
                        Split(x, rq - 1, b, c);
                        Split(b, rp, a, b);
                        int ac = Merge(a, c);
                        ans += f[ac].ans + f[b].ans;
                    }
                    else {
                        int a, b, c;
                        Split(x, rp, b, c);
                        Split(b, rq - 1, a, b);
                        int ac = Merge(a, c);
                        ans += f[ac].ans + f[b].ans;
                    }
                }
                else {
                    ans -= f[x].ans + f[y].ans;
                    int rp = Rank(p), rq = Rank(q);
                    int a, b, c, d;
                    Split(x, rp, a, b);
                    Split(y, rq - 1, c, d);
                    int r = Merge(Merge(a, d), Merge(c, b));
                    ans += f[r].ans;
                }
                
            }
            else if (op == 2) {
                ans -= f[Find(p)].ans;
                ModifyH(Find(p), Rank(p), q);
                ans += f[Find(p)].ans;
            }
            else {
                ans -= f[Find(p)].ans;
                ModifyF(Find(p), Rank(p), q);
                ans += f[Find(p)].ans;
            }
            ans = (ans % P + P) % P;
            printf("%lld\n", ans);
        }
        return 0;
    }
    
    • 1

    信息

    ID
    8118
    时间
    1000ms
    内存
    128MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者