线段树历史和

前言

  • 啥都忘了,咋办啊!

线段树历史区间和

  • 我们考虑正常线段树按顺序执行 \(m\) 次区间加操作,我们会有 \(m\) 个时刻的线段树状态。
  • 这时候我们历史区间和线段数,存的值就是 \(m\) 个时刻线段树累加的结果。
  • 想要维护这种结构,和直接维护,区间加,区间修改线段数的区别在于,我们需要考虑时间 \(t\)
  • 我们假设在 \(x\) 时刻区间加 \([l,r]+v\),现在我们在 \(t\) 时刻 \((x\le t)\) 查询的时候,\([l,r]\) 的历史区间和是 \((t-x+1)v(r-l+1)\)
  • 我们只关心当前的 \(t\),而之前的 \(x\) 我们可以拆贡献计算。于是 \((t+1)v\times len-xv\times len\)
  • 这里我们对于线段树的每一个节点,记录 \(sum\) 区间和,\(hsum\) 历史区间和。
  • 这是解释一下 \(sum=\sum v_i\)\(hsum=\sum -x_iv_i\)\(ans=sum\times (t+1)-hsum\) 就行了。
  • 但是为了维护 \(sum,hsum\) 需要两个懒标记,\(tsum,thsum\),具体详见参考实现,其实还有矩阵写法,可我太菜了,不会啊
struct lr { int l, r; lr(int x) { l = r = x; }lr(int x, int y) { l = x; r = y; } };
namespace xds2
{
    struct xdsnode { int ls, rs; uint s, hs, ts, ths; }t[N * 120];
    int tim;
    void newnode(int& x)
    {
        static int idx = 0; ++idx;
        t[idx] = t[x]; x = idx;
    }
    void bdown(int x, uint v1, uint v2, uint len)
    {
        t[x].s += v1 * len; t[x].hs += v2 * len;
        t[x].ts += v1; t[x].ths += v2;
    }
    void down(int x, int l, int r, int m)
    {
        if (t[x].ls || t[x].ths)
        {
            newnode(t[x].ls); newnode(t[x].rs);
            bdown(t[x].ls, t[x].ts, t[x].ths, m - l + 1);
            bdown(t[x].rs, t[x].ts, t[x].ths, r - m);
            t[x].ts = t[x].ths = 0;
        }
    }
    void up(int x)
    {
        t[x].s = t[t[x].ls].s + t[t[x].rs].s;
        t[x].hs = t[t[x].ls].hs + t[t[x].rs].hs;
    }
    void upd(int& x, int l, int r, int L, int R, uint v)
    {
        newnode(x);
        if (L <= l && r <= R)return bdown(x, v, -v * (tim - 1), r - l + 1);
        int m = l + r >> 1; down(x, l, r, m);
        if (L <= m)upd(t[x].ls, l, m, L, R, v);
        if (R > m)upd(t[x].rs, m + 1, r, L, R, v); up(x);
    }
    uint ask(int x, int l, int r, int L, int R)
    {
        if (L <= l && r <= R)return t[x].hs + t[x].s * tim;
        int m = l + r >> 1; down(x, l, r, m);
        if (R <= m)return ask(t[x].ls, l, m, L, R);
        if (L > m)return ask(t[x].rs, m + 1, r, L, R);
        return ask(t[x].ls, l, m, L, R) + ask(t[x].rs, m + 1, r, L, R);
    }
    struct xds
    {
        int rt; uint tm;
        struct xdsit
        {
            lr a; xds* rt;
            void operator+=(uint add) { tim = rt->tm; upd(rt->rt, 1, n, a.l, a.r, add); }
            operator uint() { tim = rt->tm; return ask(rt->rt, 1, n, a.l, a.r); }
        };
        xdsit operator[](const lr& x) { return { x,this }; }
    };
}
posted @ 2025-02-23 12:11  LUHCUH  阅读(211)  评论(1)    收藏  举报