专栏文章
动态开点线段树优化
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mimzytie
- 此快照首次捕获于
- 2025/12/01 18:19 3 个月前
- 此快照最后确认于
- 2025/12/01 18:19 3 个月前
压缩
题目
时间限制:1000 ms
空间限制:64 MB
空间限制:64 MB
题目描述
令 。
如题,已知一个长度为 的数列 (),初始时 序列满足 。你需要进行下面两种操作:
- 将某一个数改为 。
- 求出某区间每一个数的异或和,并将结果写入 。
初始为 。本题强制在线,具体看输入格式。
输入格式
第一行包含一个整数 ,表示操作的总个数。
接下来 行每行包含 个整数,表示一个操作。将每个数异或 后,内容具体如下:
1 i k:将 改为 。2 l r:输出 内每个数的异或和,并将结果写入 。
比如,输入了 ,则其实际值为。
输出格式
输出包含若干行整数,即为所有操作 2 的结果。
说明/提示
保证 ,,。]
定义高度为与叶子的距离,叶子的高度为 0.
对于每个节点,维护其左子节点(含)下最高的节点;右同理.
CPPtypedef std::size_t S;
struct No {
S L, R, x;
No *c[2];
};
#define lc (p->c[0])
#define rc (p->c[1])
宏定义一会有用。
修改
递归修改 。当递归到一个节点 时:
- 判断是否可以直接修改;
- 判断在哪侧 ;
- 如果 不存在,创建;
- 否则如果 在 内,递归;
- 否则创建其 LCA 并将两点放在其两侧(一定在两侧)。
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 条评论,欢迎与作者交流。
正在加载评论...