找回密码
 立即注册
首页 业界区 业界 提高组线段树汇总

提高组线段树汇总

箝德孜 2025-7-30 08:53:39
下标线段树

下标线段树即最普通的线段树,用来维护一个区间 \([L,R]\) 的信息,可以发现这其实对应了数组里面的下标,故称其为下标线段树
基本原理

对于每个节点 \([l,r]\),左儿子是 \([l,mid]\),右儿子是 \([mid+1,r]\),\(mid=(l+r)/2\)(向下取整)
我们发现除了最后一层是一个满二叉树,于是我们就可以用与二叉堆类似的方法存储
对于一个编号为 \(x\) 的节点,父亲节点 \(x/2\)(x >> 1)(向下取整),左儿子 \(2x\)(x  1;    build(u  mid\) 只递归右边
剩下的情况需要递归左边和右边,这种情况最多发生一次,之后便会变成上述两种情况。因此复杂度为 \(O(2\log n)\) 忽略常数还是 \(O(\log n)\) 的

  • \([L,R]\cap[T_L,T_R]= \varnothing\),这种情况是不存在的
总结一下操作过程:

  • 若 \([l,r]\) 完全覆盖了当前节点所覆盖的区间,则立即回溯,并且该节点的值做为一个备选答案
  • 若左子节点与 \([l,r]\) 有重叠部分,则递归访问左子节点
  • 若右子节点与 \([l,r]\) 有重叠部分,则递归访问右子节点
push down:给一个区间加上一个数,更新到两个子节点
例题

I. [JSOI2008] 最大数

因为动态添加比较麻烦,所以我们直接建 \(1\sim m\) 个空间就行了(最多 \(m\) 个操作,也就是 \(m\) 个空间),每次新增一个数的时候相当于直接修改,问后 \(L\) 个数里面最大值就是问 \([n-L+1,n]\)(\(n\) 在每次加数的时候也顺带 ++)
[code]#include using namespace std;const int N = 200005;struct Node{    int l, r; //左儿子右儿子    int v; //记录的最大值}tr[N * 4];//建树void build(int u, int l, int r){    tr = { l,r };    if (l == r) return; //叶子节点    int mid = l + r >> 1;    build(u > y;        if (k == 1)        {            if (x > y) swap(x, y);            cout  1;    if (r > r;        if (op == 'C')        {            cin >> d;            add(l, d), modify(1, l, d);            if (r < n) add(r + 1, -d), modify(1, r + 1, -d);        }        else cout

相关推荐

您需要登录后才可以回帖 登录 | 立即注册