P9069 堕天作战 Sol

倍增分块做就行。

倍增分块维护 \(\log\) 个块,第 \(i\) 个块存 \([\text{base}^i,\text{base}^{i+1})\) 之间的所有元素。

这里与 P7447 rgxsxrs 的不同之处在于对于 \(<x\) 的值也要减少 \(x\),即变为负数。

但是发现变成负数之后相当于一个区间减了,根本不需要管其他事情。

那么新开一棵线段树,插入这些已经变成负数的位置。

修改的时候分开修改,查询的时候分开查就行。

用了底层分块,但是这题不卡空间,其实不需要。

(虽然但是我删掉底层分块之后变慢了是怎么回事)

下面调了一下块长和进制。

底层分块阈值 \(\text{len}=30,\text{base}=201\) 最快是为什么呢。

有无懂哥解释一下啊。

#include <bits/stdc++.h>
using ull = unsigned long long;
using namespace std;

const int N = 5e5 + 10, M = 1e7, inf = 2e9;
namespace fast_io {
    int it, ed, ot, t; char stk[20], bf[M + 50], ob[M + 50];
    #define gc (it == ed && (ed = (it = 0) + fread(bf, 1, M, stdin), it == ed))? EOF : bf[it++]
    template <typename T> inline void read(T &x) {
        x = 0; char ch = gc; for (; !isdigit(ch); ch = gc);
        for (; isdigit(ch); ch = gc) x = x * 10 + (ch ^ 48); return ;
    } template <typename T, typename ...Args>
    inline void read(T &x, Args &...args) { read(x), read(args...); }
    inline void fls() { fwrite(ob, 1, ot, stdout), ot = 0; }
    template <typename T> inline void write(T x, char opt) {
        while (x > 9) stk[++t] = 48 ^ (x % 10), x /= 10;
        for (ob[ot++] = 48 ^ x; t; ob[ot++] = stk[t--]);
        ob[ot++] = opt; return ;
    }
} using fast_io::read; using fast_io::write;

namespace seg1 {
    #define ls ((rt) << 1)
    #define rs ((rt) << 1 | 1)
    struct Node { int len; ull tag, val; } t[N << 2];

    inline void addtag(int rt, ull val) {
        t[rt].tag += val, t[rt].val += val * t[rt].len;
        return ;
    }

    inline void pushdown(int rt) {
        if (!t[rt].tag) return ;
        addtag(ls, t[rt].tag), addtag(rs, t[rt].tag);
        return t[rt].tag = 0, void();
    }

    inline void ins(int rt, int l, int r, int pos, int val) {
        if (l == r) return t[rt].len = 1, t[rt].val = val, void();
        int mid = (l + r) >> 1; pushdown(rt);
        if (pos <= mid) ins(ls, l, mid, pos, val);
        else ins(rs, mid + 1, r, pos, val);
        return t[rt].val += val, ++t[rt].len, void();
    }

    inline void upd(int rt, int l, int r, int L, int R, int val) {
        if (L <= l && r <= R) return addtag(rt, -val);
        int mid = (l + r) >> 1; pushdown(rt);
        if (L <= mid) upd(ls, l, mid, L, R, val);
        if (R > mid) upd(rs, mid + 1, r, L, R, val);
        return t[rt].val = t[ls].val + t[rs].val, void();
    }

    inline ull query(int rt, int l, int r, int L, int R) {
        if (L <= l && r <= R) return t[rt].val;
        int mid = (l + r) >> 1; ull res = 0; pushdown(rt);
        if (L <= mid) res += query(ls, l, mid, L, R);
        if (R > mid) res += query(rs, mid + 1, r, L, R);
        return res;
    }
}

#undef ls
#undef rs

const int bas = 30, SIZ = 201;
int n, m, V, cnt, Maxb, pw[40], rot[40], a[N], bel[N];
struct Node { int Min, Max, len, tag, ls, rs; ull val; } t[N << 4];
#define ls t[rt].ls
#define rs t[rt].rs
#define getid(x) ((int)(log(x) / log(SIZ)))

inline void pushup(int rt) {
    t[rt].Min = min(t[ls].Min, t[rs].Min);
    t[rt].Max = max(t[ls].Max, t[rs].Max);
    t[rt].len = t[ls].len + t[rs].len;
    t[rt].val = t[ls].val + t[rs].val; return ;
}

inline void rebuild(int id, int rt, int l, int r) {
    t[rt].Min = inf, t[rt].Max = -inf, t[rt].len = t[rt].val = 0;
    for (int i = l; i <= r; ++i) {
        if (bel[i] != id) continue;
        t[rt].Min = min(t[rt].Min, a[i]);
        t[rt].Max = max(t[rt].Max, a[i]);
        t[rt].val += a[i], ++t[rt].len;
    }
    return ;
}

inline void addtag(int rt, int val) {
    if (!t[rt].len) return ;
    t[rt].tag += val, t[rt].Min += val, t[rt].Max += val;
    t[rt].val += (ull)t[rt].len * val; return ;
}

inline void pushdown(int id, int rt, int l, int r) {
    if (!t[rt].tag) return ;
    if (r - l >= bas) addtag(ls, t[rt].tag), addtag(rs, t[rt].tag);
    else for (int i = l; i <= r; ++i) if (bel[i] == id) a[i] += t[rt].tag;
    return t[rt].tag = 0, void();
}

inline void build(int id, int &rt, int l, int r) {
    rt = ++cnt; if (r - l < bas) return rebuild(id, rt, l, r);
    int mid = (l + r) >> 1; build(id, ls, l, mid), build(id, rs, mid + 1, r);
    return pushup(rt);
}

inline void ins(int id, int rt, int l, int r, int pos, int val) {
    if (r - l < bas) {
        pushdown(id, rt, l, r), bel[pos] = id;
        t[rt].Min = min(t[rt].Min, val);
        t[rt].Max = max(t[rt].Max, val);
        return t[rt].val += val, ++t[rt].len, void();
    }
    int mid = (l + r) >> 1; pushdown(id, rt, l, r);
    if (pos <= mid) ins(id, ls, l, mid, pos, val);
    else ins(id, rs, mid + 1, r, pos, val); return pushup(rt);
}

inline void upd(int id, int rt, int l, int r, int L, int R, int val) {
    if (t[rt].Max <= val || !t[rt].len) return ;
    else if (L <= l && r <= R && t[rt].Min - val >= pw[id]) return addtag(rt, -val);
    else if (r - l < bas) {
        pushdown(id, rt, l, r), L = max(L, l), R = min(R, r);
        for (int i = L; i <= R; ++i) {
            if (bel[i] != id || a[i] <= val) continue;
            if ((a[i] -= val) >= pw[id]) continue;
            int got = getid(a[i]); ins(got, rot[got], 1, n, i, a[i]);
        }
        return rebuild(id, rt, l, r);
    }
    int mid = (l + r) >> 1; pushdown(id, rt, l, r);
    if (L <= mid) upd(id, ls, l, mid, L, R, val);
    if (R > mid) upd(id, rs, mid + 1, r, L, R, val);
    return pushup(rt);
}

inline void down(int id, int rt, int l, int r, int L, int R, int val) {
    if (t[rt].Min >= val || !t[rt].len) return ;
    else if (r - l < bas) {
        pushdown(id, rt, l, r), L = max(L, l), R = min(R, r);
        for (int i = L; i <= R; ++i) {
            if (bel[i] != id || a[i] >= val) continue;
            bel[i] = -1, seg1::ins(1, 1, n, i, a[i] -= val);
        }
        return rebuild(id, rt, l, r);
    }
    int mid = (l + r) >> 1; pushdown(id, rt, l, r);
    if (L <= mid) down(id, ls, l, mid, L, R, val);
    if (R > mid) down(id, rs, mid + 1, r, L, R, val);
    return pushup(rt);
}

inline ull query(int id, int rt, int l, int r, int L, int R) {
    if ((L <= l && r <= R) || !t[rt].len) return t[rt].val;
    else if (r - l < bas) {
        ull res = 0; L = max(L, l), R = min(R, r);
        for (int i = L; i <= R; ++i)
            if (bel[i] == id) res += a[i] + t[rt].tag;
        return res;
    }
    int mid = (l + r) >> 1; pushdown(id, rt, l, r); ull res = 0;
    if (L <= mid) res += query(id, ls, l, mid, L, R);
    if (R > mid) res += query(id, rs, mid + 1, r, L, R);
    return res;
}

inline void init() {
    V = *max_element(a + 1, a + 1 + n), Maxb = getid(V), pw[0] = 1;
    for (int i = 1; i <= Maxb; ++i) pw[i] = pw[i - 1] * SIZ;
    for (int i = 1; i <= n; ++i) {
        if (a[i]) bel[i] = getid(a[i]);
        else seg1::ins(1, 1, n, i, 0), bel[i] = -1;
    }
    for (int i = 0; i <= Maxb; ++i) build(i, rot[i], 1, n);
    return ;
}

inline void modify(int l, int r, int val) {
    int Maxi = min(Maxb, getid(val));
    for (int i = 0; i <= Maxi; ++i) down(i, rot[i], 1, n, l, r, val);
    for (int i = Maxi; i <= Maxb; ++i) upd(i, rot[i], 1, n, l, r, val);
    return ;
}

inline ull ques(int l, int r) {
    ull res = 0;
    for (int i = 0; i <= Maxb; ++i)
        res += query(i, rot[i], 1, n, l, r);
    return res;
}

#undef ls
#undef rs

int main() {
    read(n, m); for (int i = 1; i <= n; ++i) read(a[i]);
    init(); ull res = 0;
    for (int i = 1; i <= m; ++i) {
        int op, l, r, val; read(op, l, r); l ^= res, r ^= res;
        if (op == 1) {
            read(val), val ^= res;
            if (!val) continue; seg1::upd(1, 1, n, l, r, val);
            modify(l, r, val);
        } else {
            res = 0;
            res += seg1::query(1, 1, n, l, r);
            res += ques(l, r); write(res, '\n');
            res &= ((1 << 20) - 1);
        }
    }
    return fast_io::fls(), 0;
}
posted @ 2023-03-15 00:14  MistZero  阅读(17)  评论(0编辑  收藏  举报