我们把一个数拆出最高位\(x\)和其他位\(y\)来单独考虑,例如\(5\)可以拆分成\(4\)和\(1\),那么操作一就是最高位\(x\)乘2,操作二就是其他位删除\(1\)个二进制下\(1\)的个数,如果\(y\)已经是\(0\)了,因为\(x\)只含有最高位的\(1\)个\(1\),我们还需要将\(x\)置为\(0\),当\(x\)也为\(0\)后,表示之后对于它的操作都是无效的了,我们用一个标记\(flag\)来表示它已经不需要操作了,当一个区间\(flag\)为\(true\)时,我们可以直接返回,减少复杂度。
对于有效的操作一,操作二,我们用线段树分别维护即可。
对于操作一,我们只需要区间乘\(2\)的操作。
对于操作二,我们可以暴力遍历每一个\(flag\)不为\(true\)的区间,因为每个点最多有\(log_2(1e9)\)次操作二,所以加上\(flag\)标记后时间复杂度也在可接受范围内。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 1e5 + 5;
const int MOD = 998244353;
int lowbit(int x) {
return x & -x;
}
// 找到最大的满足条件的2^k<=x
int find(int x) {
int res = 1;
while (res <= x) {
res <<= 1;
}
return res >> 1;
}
int a[MAXN], b[MAXN];
#define ls(x) (x) << 1
#define rs(x) (x) << 1 | 1
struct SegmentTreeNode {
int l, r;
int high, low; // high为最高位的值, low为其他位值
int mul; // 标记
bool flag; // 是否全部清空
int mid() {
return (l + r) >> 1;
}
}tree[MAXN << 2];
void pushup(int p) {
tree[p].high = (tree[ls(p)].high + tree[rs(p)].high) % MOD;
tree[p].low = (tree[ls(p)].low + tree[rs(p)].low) % MOD;
tree[p].flag = tree[ls(p)].flag & tree[rs(p)].flag;
}
void pushdown(int p) {
if (tree[p].mul != 1) {
tree[ls(p)].high = (tree[ls(p)].high * tree[p].mul) % MOD;
tree[rs(p)].high = (tree[rs(p)].high * tree[p].mul) % MOD;
tree[ls(p)].mul = (tree[ls(p)].mul * tree[p].mul) % MOD;
tree[rs(p)].mul = (tree[rs(p)].mul * tree[p].mul) % MOD;
tree[p].mul = 1;
}
}
void build(int l, int r, int p) {
tree[p].l = l, tree[p].r = r;
tree[p].mul = 1;
if (l == r) {
tree[p].high = a[l];
tree[p].low = b[l];
tree[p].flag = false;
return ;
}
int mid = (l + r) >> 1;
build(l, mid, ls(p));
build(mid + 1, r, rs(p));
pushup(p);
}
// 单点修改
void update1(int l, int r, int p) {
if (tree[p].flag) return ; // 全部为0直接返回
if (tree[p].l == tree[p].r) {
if (tree[p].low) {
tree[p].low -= lowbit(tree[p].low);
}
// 如果其他位值为0那么将最高位置0并标记
else {
tree[p].high = 0;
tree[p].flag = true;
}
return ;
}
pushdown(p);
int mid = tree[p].mid();
if (l <= mid) update1(l, r, ls(p));
if (r > mid) update1(l, r, rs(p));
pushup(p);
}
// 区间乘操作
void update2(int l, int r, int p) {
if (tree[p].flag) return ; // 全部为0直接返回
if (l <= tree[p].l && tree[p].r <= r) {
tree[p].mul = (tree[p].mul * 2) % MOD;
tree[p].high = (tree[p].high * 2) % MOD;
return ;
}
pushdown(p);
int mid = tree[p].mid();
if (l <= mid) update2(l, r, ls(p));
if (r > mid) update2(l, r, rs(p));
pushup(p);
}
int query(int l, int r, int p) {
if (l <= tree[p].l && tree[p].r <= r) {
return (tree[p].high + tree[p].low) % MOD;
}
pushdown(p);
int mid = tree[p].mid(), res = 0;
if (l <= mid) res = (res + query(l, r, ls(p))) % MOD;
if (r > mid) res = (res + query(l, r, rs(p))) % MOD;
return res;
}
signed main(int argc, char *argv[]) {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
int t = find(a[i]);
b[i] = a[i] - t, a[i] = t;
// a存储最高位, b存储其他位
}
build(1, n, 1);
int m;
cin >> m;
while (m--) {
int opt, l, r;
cin >> opt >> l >> r;
if (l > r) swap(l, r);
if (opt == 1) {
cout << query(l, r, 1) << '\n';
}
if (opt == 2) {
update1(l, r, 1);
}
if (opt == 3) {
update2(l, r, 1);
}
}
}
system("pause");
return 0;
}