Description
数据结构
- 区间减去
- 区间加上
- 区间求和
Solution
难度比较适中的一道题,注意到操作1最多减去 次, 个数字需要的操作次数数量级为,考虑用线段树维护区间,可以 完成操作1,最终用一个 代表这个区别是不是全为 ,因为 就不需要再操作了。
对于操作2,每次只是对最高位进行修改,不妨将最高位和其他位分离开来维护,操作2就是对最高位做一次乘以2的操作,可以单点修改完成。
Code
/* * @Author: Kurisu */ #include<bits/stdc++.h> const int N = 1e5 + 5; const int mod = 998244353; long long a[N], b[N]; long long lowbit(long long x) { return x & (-x); } namespace SegmentTree { struct node { int l, r; bool tag; long long sum1, sum2, lazy; }t[N << 2]; void push_up(int rt) { t[rt].sum1 = (t[rt << 1].sum1 + t[rt << 1 | 1].sum1) % mod; t[rt].sum2 = (t[rt << 1].sum2 + t[rt << 1 | 1].sum2) % mod; t[rt].tag = (t[rt << 1].tag and t[rt << 1 | 1].tag); } void push_down(int rt) { if (t[rt].lazy) { t[rt << 1].lazy = t[rt << 1].lazy * t[rt].lazy % mod; t[rt << 1 | 1].lazy = t[rt << 1 | 1].lazy * t[rt].lazy % mod; t[rt << 1].sum1 = t[rt << 1].sum1 * t[rt].lazy % mod; t[rt << 1 | 1].sum1 = t[rt << 1 | 1].sum1 * t[rt].lazy % mod; t[rt].lazy = 1; } t[rt << 1].tag |= t[rt].tag; t[rt << 1 | 1].tag |= t[rt].tag; if (t[rt << 1].tag) { t[rt << 1].sum1 = t[rt << 1].sum2 = 0; } if (t[rt << 1 | 1].tag) { t[rt << 1 | 1].sum1 = t[rt << 1 | 1].sum2 = 0; } } void build(int rt, int l, int r) { t[rt].l = l, t[rt].r = r; t[rt].tag = 0; t[rt].lazy = 1; if (l == r) { t[rt].sum1 = a[l]; t[rt].sum2 = b[l]; return ; } int mid = (l + r) >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); push_up(rt); } long long query(int rt, int ql, int qr) { if (ql <= t[rt].l and qr >= t[rt].r) { return (t[rt].sum1 + t[rt].sum2) % mod; } push_down(rt); int mid = (t[rt].l + t[rt].r) >> 1; long long res = 0; if (ql <= mid) { res += query(rt << 1, ql, qr); } if (qr > mid) { res += query(rt << 1 | 1, ql, qr); } return res % mod; } void update_lowbit(int rt, int ql, int qr) { if (t[rt].tag) { return ; } if (t[rt].l == t[rt].r) { if (t[rt].sum2) { t[rt].sum2 -= lowbit(t[rt].sum2); return ; } else if (t[rt].sum1) { t[rt].sum1 = 0; t[rt].tag = 1; return ; } } push_down(rt); int mid = (t[rt].l + t[rt].r) >> 1; if (ql <= mid) { update_lowbit(rt << 1, ql, qr); } if (qr > mid) { update_lowbit(rt << 1 | 1, ql, qr); } push_up(rt); } void update_bits(int rt, int ql, int qr) { if (ql <= t[rt].l and qr >= t[rt].r) { t[rt].sum1 = t[rt].sum1 * 2 % mod; t[rt].lazy = t[rt].lazy * 2 % mod; return ; } push_down(rt); int mid = (t[rt].l + t[rt].r) >> 1; if (ql <= mid) { update_bits(rt << 1, ql, qr); } if (qr > mid) { update_bits(rt << 1 | 1, ql, qr); } push_up(rt); } } void solve() { int n, q; std::cin >> n; for (int i = 1; i <= n; i++) { int x; std::cin >> x; for (int j = 31; j >= 0; j--) { if ((1LL << j) <= x) { a[i] = (1LL << j); b[i] = x - a[i]; break; } } } SegmentTree::build(1, 1, n); std::cin >> q; while (q--) { int op, l, r; std::cin >> op >> l >> r; if (op == 1) { std::cout << SegmentTree::query(1, l, r) << '\n'; } else if (op == 2) { SegmentTree::update_lowbit(1, l, r); } else if (op == 3) { SegmentTree::update_bits(1, l, r); } } } int main() { //freopen("data.in", "r", stdin); //freopen("1.out", "w", stdout); std::cin.sync_with_stdio(false), std::cin.tie(nullptr); int T = 1; std::cin >> T; while (T--) { solve(); } return 0; }