本文共 3024 字,大约阅读时间需要 10 分钟。
线段树维护范围异或标记查询问题
在处理范围异或标记查询(RSQ)问题时,线段树是一种高效的数据结构。以下是对该问题的优化叙述:
区间表示:线段树中的每个节点tree[rt]
表示其对应的区间中1的个数。这种方法允许我们在对大范围进行操作时,快速查询或更新区间信息。
懒标记处理:在处理异或操作时,懒标记tag[rt]
用于记录该节点及其子树的状态需进行的翻转操作。当tag[rt]
为1时,表示该子树区间需要翻转;若为0,则表示不需要翻转。
翻转优化:由于翻转操作是一个可交换的操作,翻转偶数次相当于没有翻转。因此在进行懒标记推送时,如果当前节点需要翻转(tag[rt] == 1
),则推送操作应对子树节点进行翻转,并将标记tag[rt]
设为0,以避免重复处理。
数据更新:在进行区间翻转时,利用当前节点覆盖范围判断是否需要对子树进行翻转。如果当前节点的范围完全在更新的区间内,则对该节点的计数值进行翻转,并标记tag[rt]
进行状态更新。如果节点的范围部分重叠,则需要先将懒标记推送到子树节点,然后再处理子节点的更新。
查询处理:在进行查询时,必须先将懒标记推送到子树节点,以确保查询的准确性。推送步骤包括计算中间分割点,并递归调用子节点进行查询。
时间复杂度:使用线段树进行懒标记处理的优势在于,更新和查询操作的时间复杂度均为O(log n),这使得该方法在处理大量数据时非常高效。
下面的代码实现了上述逻辑,能够有效地维护区间翻转和查询操作。
线段树维护范围异或标记查询问题
在处理范围异或标记查询(RSQ)问题时,线段树是一种高效的数据结构。
线段树中的每个节点`tree[rt]`表示其对应的区间中1的个数。
在处理异或操作时,懒标记`tag[rt]`用于记录该节点及其子树的状态需进行的翻转操作。
由于翻转操作是一个可交换的操作,翻转偶数次相当于没有翻转。因此在进行懒标记推送时,如果当前节点需要翻转(`tag[rt] == 1`),则推送操作应对子树节点进行翻转,并将标记`tag[rt]`设为0,以避免重复处理。
在进行区间翻转时,利用当前节点覆盖范围判断是否需要对子树进行翻转。
如果当前节点的范围完全在更新的区间内,则对该节点的计数值进行翻转,并标记`tag[rt]`进行状态更新。如果节点的范围部分重叠,则需要先将懒标记推送到子树节点,然后再处理子节点的更新。
在进行查询时,必须先将懒标记推送到子树节点,以确保查询的准确性。
推送步骤包括计算中间分割点,并递归调用子节点进行查询。
下面的代码实现了上述逻辑,能够有效地维护区间翻转和查询操作。
#include
using namespace std;#define ll long longconst int maxn = 1e5 + 7;const int INF = 0x3f3f3f3f;int tree[maxn*4], tag[maxn*4];int n, m;inline int lc(int & rt) { return rt < 1 ? 0 : tree[rt]; }inline int rc(int & rt) { return rt < 1 ? 0 : tree[rt]; }inline void pushup(int & rt) { tree[rt] = tree[lc(rt)] + tree[rc(rt)]; }void build(int rt, int l, int r) { if (l == r) { tree[rt] = 0; } else { int mid = (l + r) >> 1; build(lc(rt), l, mid); build(rc(rt), mid + 1, r); pushup(rt); }}void pushdown(int rt, int l, int r) { if (tag[rt]) { int mid = (l + r) >> 1; tree[lc(rt)] = mid - l + 1 - tree[lc(rt)]; // 原本全是1的变成0 tag[lc(rt)] ^= 1; tree[rc(rt)] = r - mid - tree[rc(rt)]; // 原本全是1的变成0 tag[rc(rt)] ^= 1; tag[rt] = 0; }}void updata(int rt, int l, int r, int vl, int vr) { if (vr < l || vl > r) return; if (vl <= l && r <= vr) { tree[rt] = r - l + 1 - tree[rt]; // 数量取反 tag[rt] ^= 1; return; } int mid = (l + r) >> 1; pushdown(rt, l, r); updata(lc(rt), l, mid, vl, vr); updata(rc(rt), mid + 1, r, vl, vr); pushup(rt);}int query(int rt, int l, int r, int vl, int vr) { if (vr < l || vl > r) return 0; if (vl <= l && r <= vr) { return tree[rt]; } int mid = (l + r) >> 1; pushdown(rt, l, r); return query(lc(rt), l, mid, vl, vr) + query(rc(rt), mid + 1, r, vl, vr);}int main() { scanf("%d %d", & n, & m); // 选择性初始化,树初始为0,省去build函数 while (m--) { int f; scanf("%d", & f); if (f == 1) { int x, y; scanf("%d %d", & x, & y); updata(1, 1, n, x, y); } else { int x; scanf("%d", & x); printf("%d\n", query(1, 1, n, x, x)); } } return 0;}
转载地址:http://qzjyk.baihongyu.com/