ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

势能线段树

2022-08-19 16:30:28  阅读:138  来源: 互联网

标签:势能 int lowbit 线段 interval ai


势能线段树

什么是势能线段树

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有