其他分享
首页 > 其他分享> > 势能线段树

势能线段树

作者:互联网

势能线段树

什么是势能线段树

所谓势能线段树,是指在懒标记无法正常使用的情况下,暴力到叶子将线段树当成数组一样用进行修改。
大概就是先暴力,在暴力到一个状态的时候再用lazy标记。

D. Lowbit

题意:

一个数组,两个操作

  1. 1 L R, add lowbit(ai) each ai in the interval [L,R].
  2. 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