博客
关于我
P5057 [CQOI2006]简单题 (线段树入门)
阅读量:796 次
发布时间:2019-03-25

本文共 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/

    你可能感兴趣的文章
    Linux kernel pwn --- CSAW2015 StringIPC
    查看>>
    配置jdk的环境变量
    查看>>
    编译android源代码(aosp)
    查看>>
    IDEA 找不到 Persistence窗口解决办法
    查看>>
    维基百科之AndroidRoot
    查看>>
    C++ Primer Plus读书笔记:循环读取(错误处理)
    查看>>
    skimage与cv2 安装失败的解决办法
    查看>>
    关于吴恩达的深度学习的一些授课视频里面英文翻译错误的实例展示
    查看>>
    伴随矩阵和逆矩阵的关系证明
    查看>>
    突破Bias-Variance困境
    查看>>
    Form窗体属性
    查看>>
    解决Eclipse加载图片或网页出现404错误
    查看>>
    vue 错误收集
    查看>>
    Java选择排序算法实现
    查看>>
    00010.02最基础客户信息管理软件(意义类的小项目,练习基础,不涉及数据库)
    查看>>
    00013.05 字符串比较
    查看>>
    IEDA全局搜索快捷键 Ctrl+shift+F无效的原因、 eclipse:Ctrl + h 进行全局搜索
    查看>>
    LeetCode: 138. 复制带随机指针的链表(中等)[DFS, 迭代]
    查看>>
    Effective Java 读书笔记
    查看>>
    SpringBoot使用@Email报错误
    查看>>