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

势能线段树

时间:2022-08-19 16:36:15浏览次数:87  
标签:势能 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
From: https://www.cnblogs.com/hxxO-o/p/16602408.html

相关文章

  • 线段树小结
    线段树线段树二分线段树分治可持久化线段树线段树合并线段树分裂线段树维护单调栈李超线段树势能线段树&吉司机线段树线段树套···都咕掉了。......
  • 李超线段树学习笔记
    这个hack数据是真的强。模板题的题解很重要哦,希望你能找到适合自己的。博客食用更佳哦李超线段树的定义对于李超线段树的定义,JHSeng大佬的定义简洁精炼:李超线段树是一......
  • #10007. 「一本通 1.1 练习 3」线段
    #include<bits/stdc++.h>usingnamespacestd;structnode{ intl,r;};boolcmp(nodex,nodey){ returnx.r<y.r;}classSolution{ public: intsolve(vector......
  • 开关(线段树区间异或板子)
    [TJOI2009]开关题目描述现有\(n\)盏灯排成一排,从左到右依次编号为:\(1\),\(2\),……,\(n\)。然后依次执行\(m\)项操作。操作分为两种:指定一个区间\([a,b]\),然后改变......
  • 172 树套树 线段树套平衡树
    视频链接:LuoguP3380【模板】二逼平衡树(树套树)//需要开O2#include<iostream>#include<algorithm>usingnamespacestd;#defineN2000010#defineINF21474836......
  • 线段树模板【带懒标记】
    #include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=1e5+10;inta[N];structnode{  intl,r;  lladd,sum;  node(){  ......
  • YbtOJ 「数据结构」第4章 线段树
    不想dp了怎么办?开个新坑吧。例题1.求区间和树状数组不香吗,28行解决(bushi所以懒得打线段树了。code#include<bits/stdc++.h>#defineintlonglongusingnamespac......
  • 洛谷 P6242 【模板】线段树 3 吉司机线段树 区间取最小值 维护历史最大值和区间和
    题目背景本题是线段树维护区间最值操作与区间历史最值的模板。题目描述给出一个长度为 nn 的数列 AA,同时定义一个辅助数组 BB,BB 开始与 AA 完全相同。接下来......
  • 线段树----区间问题的神
    《标准线段树》  普通的线段树,其区间一般都是一个序列的数的个数,但还是要根据不同题目来判断注意:tr[]空间是N*4,N为最大范围《单点修改,区间查询》原题:https://www.......
  • 动态开点线段树
    动态开点线段树为了准备google的面试刷题的时候发现这个知识点其实我一直不太熟悉,所以专门写一篇blog准备一下。我们将从以下几个方面去讲解:目录动态开点线段树什么是......