zoukankan      html  css  js  c++  java
  • 「学习笔记」优美的暴力——莫队

    前置芝士

    分块的思想。
    暴力

    字母/变量的含义

    (n):序列的长度。
    (q):询问个数。
    (d):块的大小。
    (num[i])(i)这个元素所在的块的编号。
    (q[i]):一个询问。
    (q[i].x):一个询问的左端点。
    (q[i].y):一个询问的右端点。
    (q[i].id):一个询问的编号。

    普通莫队

    考虑这样一个问题:

    一个长为 (n) 的序列,(q) 次询问,每次询问 ([l,r]) 这个区间的元素的和。

    (0 < n,q leq 100000)

    考虑暴力,每次扫描 ([l,r]) 这个区间的到答案复杂度 (O(n ^2))

    考虑优化,假如已知 ([x,y]) 这个区间的答案,下次询问 ([x - 2, y + 2]) 的答案,可以从上一个答案转移出来。

    但这样有可能会被卡比如 ([1,1])([n,n]) 交替问你。

    再考虑优化,对询问离线,按照一种规则去排序,使得左右指针移动次数尽可能少。

    排序规则为:先对序列分块,左端点在同一块内的按右端点升序,否则按块的序号升序。

    普通莫队的要求:

    • 已知 ([l,r]) 的答案要能够 (O(1)) 的转移出 ([l - 1, r], [l, r - 1], [l + 1, r], [l, r + 1]) 的答案。
    • 可以离线。
    • 无修改。

    这样的复杂度:

    • 同一块内的询问右端点最多总共移动 (n) 次,有 (largefrac{n}{d}) 复杂度为 (largefrac{n ^ 2}{d}),换块时,右端点最多移动 (n) 次,最多换 (largefrac{n}{d}) 次块,复杂度为 (largefrac{n ^ 2}{d})

    带修莫队

    多了一个修改的操作,(应该是单点修改,窝还没见过区间修改的),改了一个点可以当做将一个数移除并加入了一个数,类似普通莫队也可以暴力来做。

    回滚莫队

    在当前已知的区间中要加入元素或移除元素来得到新的答案,可能其中一种操作很难做到 (O(1))

    那么就想到都变成一种操作。对于一个块内的 (O(d)) 来统计答案。

    如果移除元素不好做就按下面的方式排序

    struct query {//存询问的结构体
        int x, y, id;
        friend bool operator < (query q1, query q2) {
            if (num[q1.x] != num[q2.x]) return num[q1.x] < num[q2.x];
            return q1.y < q2.y;
        }
    }q[MAXN];
    

    询问的左端点和右端点不在一个块内的话,对于左端点在同一块内的这一类型的询问,右端点一定递增,左端点所在的块暴力计算 (O(d)),右端点的可以继承所以是 (O(n))
    按照这个思想,每一个块,左端点应该设为 (min(num[q[i].x] imes d, n) + 1),右端点应该设为 (min(num[q[i].x] imes d, n))
    如果加入元素不好做就按照下面的方式排序

    struct query {//存询问的结构体
        int x, y, id;
        friend bool operator < ( query q1, query q2) {
            if (num[q1.x] != num[q2.x]) return num[q1.x] < num[q2.x];
            return q1.y > q2.y;
        }
    }q[MAXN];
    

    询问的左端点和右端点不在一个块内的话,对于左端点在同一块内的这一类型的询问,右端点一定递减,左端点所在的块暴力计算 (O(d)),右端点的可以继承所以是 (O(n))
    按照这个思想,每一个块,左端点应该设为 ((num[q[i].x] - 1) imes d),右端点应该设为 (n)

    看几个题
    P5906 【模板】回滚莫队&不删除莫队
    题解
    AtCoder 1219 歴史の研究
    上面俩是删除操作不好搞的。
    P4137 Rmq Problem / mex
    这个是加数的操作不好搞的,需要卡卡常。

    树上莫队

    用欧拉序将树上变成序列上

    想不到这么短吧,有时间再改

  • 相关阅读:
    JAVA第三周学习总结
    20175303 2018-2019-2 《Java程序设计》第2周学习总结
    20175310 MyCP(课下作业,必做)
    20175310 《Java程序设计》第8周学习总结
    2018-2019-2 20175310 实验二《Java面向对象程序设计》实验报告
    20175310 《Java程序设计》第7周学习总结
    结对编程项目-四则运算 整体总结博客
    20175310 《Java程序设计》第6周学习总结
    20175310结对编程项目-四则运算 阶段总结博客
    20175310 类定义
  • 原文地址:https://www.cnblogs.com/poi-bolg-poi/p/13494859.html
Copyright © 2011-2022 走看看