https://acm.hdu.edu.cn/showproblem.php?pid=7059

可以将每段区间的和转换成最高位的和+其他位的和.

  • 查询 sum = lsum + rsum
  • 减: 每个节点最多有三十次减操作,类似sqrt那个题目,直接在l==r的时候单点修改,注意需要判断当前能否减的条件是lsum > 0
  • 加: 显然是节点最高位的和*2即可,维护lz表示倍数
const int maxn = 1e5 + 7;
const int mod = 998244353;

int n, t, m;
int a[maxn];

struct node {
    ll l, r, lz, lsum, rsum;
} tr[maxn << 2];

void add(int p, int lz) {
    tr[p].lz = lz * tr[p].lz % mod;
    tr[p].lsum = tr[p].lsum * lz % mod;
}

void push_down(int p) {
    if (tr[p].lz != 1) {
        add(p << 1, tr[p].lz);
        add(p << 1 | 1, tr[p].lz);
        tr[p].lz = 1;
    }
}

void push_up(int p) {
    tr[p].lsum = (tr[p << 1].lsum + tr[p << 1 | 1].lsum) % mod;
    tr[p].rsum = (tr[p << 1].rsum + tr[p << 1 | 1].rsum) % mod;
}

void build(int p, int l, int r) {
    tr[p].l = l, tr[p].r = r, tr[p].lz = 1;
    tr[p].lsum = tr[p].rsum = 0;
    if (l == r) {
        tr[p].lsum = a[l];
        for (int i = 30; i >= 0; i--) {
            if (a[l] & (1 << i)) {
                tr[p].lsum = (1 << i);
                tr[p].rsum = a[l] - tr[p].lsum;
                break;
            }
        }
        return;
    }
    int mid = (l + r) >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
    push_up(p);
}

void update(int p, int l, int r, int opt) {
    if (tr[p].lsum == 0) return;
    if (opt == 2) {
        if (tr[p].l == tr[p].r) {
            if (tr[p].rsum == 0) tr[p].lsum = 0;
            else tr[p].rsum -= (tr[p].rsum & (-tr[p].rsum));
            return;
        }
    } else {
        if (l <= tr[p].l && tr[p].r <= r) {
            add(p, 2);
            return;
        }
    }
    push_down(p);
    int mi = (tr[p].l + tr[p].r) >> 1;
    if (l <= mi) update(p << 1, l, r, opt);
    if (r > mi) update(p << 1 | 1, l, r, opt);
    push_up(p);
}

ll res = 0;

void query(int p, int l, int r) {
    if (l <= tr[p].l && tr[p].r <= r) {
        res += (tr[p].lsum + tr[p].rsum);
        res %= mod;
        return;
    }
    push_down(p);
    int mi = (tr[p].l + tr[p].r) >> 1;
    if (l <= mi) query(p << 1, l, r);
    if (r > mi) query(p << 1 | 1, l, r);
    push_up(p);
}

void solve() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        build(1, 1, n);
        scanf("%d", &m);
        for (int i = 1, opt, l, r; i <= m; i++) {
            scanf("%d%d%d", &opt, &l, &r);
            if (opt == 1) {
                res = 0, query(1, l, r);
                printf("%lld\n", res);
            } else {
                update(1, l, r, opt);
            }
        }
    }
}

我看见 你