专栏文章

动态开点线段树优化

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mimzytie
此快照首次捕获于
2025/12/01 18:19
3 个月前
此快照最后确认于
2025/12/01 18:19
3 个月前
查看原文

压缩

题目
时间限制:1000 ms
空间限制:64 MB

题目描述

n=263n = 2^{63}
如题,已知一个长度为 nn 的数列 {ai}\{a_i\}0i<n0 \leq i < n),初始时 aa 序列满足 ai=0a_i = 0。你需要进行下面两种操作:
  1. 将某一个数改为 kk
  2. 求出某区间每一个数的异或和,并将结果写入 LL
LL 初始为 00。本题强制在线,具体看输入格式。

输入格式

第一行包含一个整数 mm,表示操作的总个数。
接下来 mm 行每行包含 33 个整数,表示一个操作。将每个数异或 LL 后,内容具体如下:
  1. 1 i k:将 aia_i 改为 kk
  2. 2 l r:输出 alara_l \sim a_r 内每个数的异或和,并将结果写入 LL
比如,输入了 a,b,ca,b,c,则其实际值为aL,bL,cLa\oplus L,b\oplus L,c\oplus L

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

说明/提示

保证 1m1061 \le m\le {10}^60lr<n0 \le l \le r <n0k<n0 \le k < n。]
定义高度为与叶子的距离,叶子的高度为 0.
对于每个节点,维护其左子节点(含)下最高的节点;右同理.
CPP
typedef std::size_t S;
struct No {
  S L, R, x;
  No *c[2];
};
#define lc (p->c[0])
#define rc (p->c[1])
宏定义一会有用。

修改

递归修改 aika_i \leftarrow k。当递归到一个节点 pp 时:
  • 判断是否可以直接修改;
  • 判断在哪侧 jj
  • 如果 jj 不存在,创建;
  • 否则如果 iijj 内,递归;
  • 否则创建其 LCA 并将两点放在其两侧(一定在两侧)。
CPP

void pushup(No* p) {
  p->x = lc->x + rc->x;
}
void update(No* p, S i, S k) {
  if (p->L == p->R - 1) {
    p->x = k;
    return;
  }
  S L = p->L, r = p->R;
  S mid = L + ((R - L) >> 1);
  No*& s = p->c[i >= mid];
  if (s) {
    if (s->L <= i && i < s->R)
      update(s, i, k);
    else {
      S t = SIZE_MAX >> __builtin_clzll(s->L ^ i), u = ~t & i;
      No* v = s;
      if (i >= v->R)
        s = new No {u, u + t + 1, 0, {v, new No{i, i, k}}};
      else
        s = new No {u, u + t + 1, 0, {new No{i, i, k}, v}};
      pushup(s);
    }
  } else {
    s = new No {i, i, k};
  }
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...