势能线段树
作者:互联网
势能线段树
什么是势能线段树
所谓势能线段树,是指在懒标记无法正常使用的情况下,暴力到叶子将线段树当成数组一样用进行修改。
大概就是先暴力,在暴力到一个状态的时候再用lazy标记。
D. Lowbit
题意:
一个数组,两个操作
- 1 L R, add lowbit(ai) each ai in the interval [L,R].
- 2 L R, query the sum of the numbers in the interval [L,R].
思路:
对于每一个ai 而言,最后进行 32次+ lowbit操作就会把这个值变成一个2的幂,然后如果再+lowbit的话就相当于把这个数 * 2,然后我们用一个falg记录一个值能不能统一 * 2,就变成了区间 乘 2 区间求和问题。
Code
const int N = 1e5 + 100, mod = 998244353, INF = 1e10;
int lowbit(int x) { return x & -x; }
int gcd(int a, int b) { return a % b == 0 ? b : gcd(b, a % b); }
/*
1. 1 L R, add lowbit(ai) to each ai in the interval [L,R]. *2
2. 2 L R, query the sum of the numbers in the interval [L,R]. 求和
*/
struct T {
int l, r;
int sum, mul; //乘
int falg; //是否能够继续,也就是看能不能直接 区间*2
} tr[N << 2];
int w[N];
void pushup(T &rt, T l, T r) {
rt.sum = l.sum + r.sum;
rt.sum %= mod;
rt.falg = l.falg & r.falg;
// 只有一个区间内部全部都能 用 *2 代替 才代表这个大区间能够代替
}
void pushup(int u) { pushup(tr[u], tr[u << 1], tr[u << 1 | 1]); }
void pushdown(int u) {
if (tr[u].falg) {
// 只有能够 *2 才传下去
tr[u << 1].mul = tr[u << 1].mul * tr[u].mul % mod;
tr[u << 1 | 1].mul = tr[u << 1 | 1].mul * tr[u].mul % mod;
tr[u << 1].sum = tr[u << 1].sum * tr[u].mul % mod;
tr[u << 1 | 1].sum = tr[u << 1 | 1].sum * tr[u].mul % mod;
tr[u].mul = 1;
}
}
void build(int u, int l, int r) {
tr[u] = {l, r, 0, 1, 0};
if (l == r) {
tr[u].sum = w[l];
return;
}
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
// query 没啥说的,一样的
int query(int u, int l, int r) {
if (tr[u].l >= l && tr[u].r <= r) {
return tr[u].sum;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
int res = 0;
if (mid >= l) res += query(u << 1, l, r);
if (mid < r) res = (res + query(u << 1 | 1, l, r)) % mod;
return res % mod;
}
// modify和普通的 线段树有一定区别
void modify(int u, int l, int r) {
// 如果变成了点
if (tr[u].l == tr[u].r) {
if (tr[u].falg) {
// 如果可以乘2 就乘2
tr[u].sum = tr[u].sum * 2 % mod;
} else {
// 直接+ lowbit
tr[u].sum = tr[u].sum + lowbit(tr[u].sum);
// 如果 成为了 2的幂 就代表这个点能够 用*2 代替,就falg=1
if (lowbit(tr[u].sum) == tr[u].sum) tr[u].falg = 1;
}
return;
}
// 如果一个区间包含了,同时这个区间能够用 *2 代替的话 就直接 lz *2 就行。
if (tr[u].l >= l && tr[u].r <= r && tr[u].falg) {
// cout << tr[u].sum << endl;
tr[u].mul = tr[u].mul * 2 % mod;
tr[u].sum = tr[u].sum * 2 % mod;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (mid >= l) modify(u << 1, l, r);
if (mid < r) modify(u << 1 | 1, l, r);
pushup(u);
}
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> w[i];
build(1, 1, n);
int q;
cin >> q;
while (q--) {
int t, x, y;
cin >> t >> x >> y;
if (t == 1) {
modify(1, x, y);
} else {
cout << query(1, x, y) << endl;
}
}
}
signed main() {
kd;
int _;
_ = 1;
cin >> _;
while (_--) solve();
return 0;
}
标签:势能,int,lowbit,线段,interval,ai 来源: https://www.cnblogs.com/hxxO-o/p/16602408.html