分治与分块

分治与分块

重制版笔记,很多地方还留了坑。。

其中穿插了重量平衡树

分治

CDQ 分治

本质上是考虑左边对右边的影响,问题变成了先加入再查询的问题

  • 离线算法

  • 处理 D 维数点时间是 $ O(nlog^{D-1}n) $

    D 维数点用KDTree:$ O(n^{\frac{D-1}{D}}) $

    D 维数点用Bitset:$ O(\frac{Dn^2}w) $ *

  • 加点,给定 $ a , b $ 查询最大的 $ ax+by $

    本质上是维护动态凸壳 *

    • 直接set维护

      记录全局变量,做插入的时候按照 x 比较,做询问按照斜率比较

      因为set里面x递增,斜率也递增

    • CDQ 分治

      solve( l , r ) ,先 solve( l , m ) solve( m + 1 , r )

      然后就变成了静态问题,左边点加进去,右边的询问。

      静态凸壳!

      右边斜率排序,然后类似归排扫一遍就好了。

  • CF 848C

    维护每个数字的位置和上一次出现的位置,价值是 i - pre i

    一段区间的价值就是 $ \displaystyle\sum_{l\leq i \leq r , pre[i] \geq l} i - pre[i] $

    本质上类似差分

    修改本质上只会修改 pre 指向这个点的,这个点,还有它的prev,只会改变三个值。

    带修改的二维数点本质上是三维数点,时间是一维。 $ O(nlog^2n) $

    可以写一下

分治FFT

前段时间学过吧

  • uoj 50

    求解微分方程 $ f'(x) = f^2(x) p(x) + 1 $

    算出来的式子是 $ \displaystyle \frac{1}{n} \sum_{0\leq i+j\leq n-1} f_if_jp_{n-1-i-j} $

    分治吧,貌似就是分治fft套路

    先solve( l , m )

    然后考虑新求出的左边的值对右边的贡献

    然后就要用 $ f_{l...mid} f_{0...r-l} p_{0...r-1} $ 卷起来

    然后就把 $ m+1...r $ 更新进 $ f_{m+1...r} $

    式子可能有点小锅(比如+1-1啥的),需要再推一下。。

线段树分治(暑假讲的叫时间分治)

  • 离线动态图连通性

    把每条边的存活时间放到序列上,然后就可以在线段树上dfs,撤销并查集解决问题

    这里要按大小合并,才可以让撤销的量很少

    可以LCT维护删除时间的最大生成树,也是离线

  • 对每个物品,求不包含它的背包 方案数

    线段树分治

    solve( l , r , f ) f 表示 把 $ l , r $ 外面的物品加入的数组

    \(f_1\) 表示 \(f\) 中加入 mid + 1 ... r 的物品

    \(f_2\) 表示 \(f\) 中加入 l ... mid

    然后递归下去 $ O(nwlogn) $ 一个物品会被加入 $ logn $ 次

  • 城市建设

    修改边权,求MST和

    还是可以对时间建立线段树,求出每个边存活时间

    LCT 一个 log,线段树分治一个 log,很慢,不需要动脑子

    修改一条边边权实际上只会影响MST一条边

    随着修改MST变化是很少的

    $ solve(l,r) $ 表示 $ l , r $ 的修改

    整个MST只会改 $ O(r-l) $ 边,其他大多数边是不变的

    能不能把会变的边拿出来跑MST?

    假设边集(l...r修改的边)是 $ S $ ,先把其中边设置为 +inf

    把这些边和剩余的边跑MST,然后现在不在MST中的边就可以删除了。

    因为这些边只会变小,只会把MST的边给拖出来

    现在边数边成了 $ O(n + |S|) $

    然后再设置成 -inf,再跑一次MST,现在在MST中的边一定最后也在MST中

    点数变成了 $ O(|S|) $,因为这些边已经可以用并查集并起来了。

    而 $ n $ 其实是上一层的点数,也就是 $ O(2(r-l)) $

    所以这一层的复杂度也是 $ O(r-l) $ 的

    $ T(n) = 2T(\frac{n}{2}) + O(nlogn) $

    $ O(nlog^2n) $ 这里的 log 是排序

    有点难写吧(可以写一下

    核心思想:修改影响的边数量很少

二进制分组

  • 二项堆

    一种可并堆,和二进制分组的思想类似。

    $ T_k $ 表示的堆是 $ T_{k-1} $ 再挂了个 $ T_{k-1} $ ,然后节点数量就是 $ 2^{k-1} $

    11个数字的二项堆就是一个点数为 8+2+1的森林

    合并两个二项堆就是类似二进制+法。

    合并是 $ log $ 的

    删除元素,其实也是合并,比如从16的堆删除就是 1,2,4,8, 的堆和剩下的堆合并。

  • 维护向量序列,支持末尾加入元素,末尾删除元素,求 $ l,r $ 和 $ (x,y) $ 的最大点积

    二进制分组解决的问题往往是,重构很简单,插入删除很麻烦的东西。比如凸壳这种东西,重构直接做,但是插入删除很难。

    如果只有增加的话,加入当前有21个元素,我们记做三组 16 + 4 + 1

    每组都建一个数据结构,支持区间查询,并且重构很快(线性就很优秀),插入删除很慢。

    你往后面加入一个元素,就和前面一步一步合并(重构)过去,比如刚刚那个21的例子,加入一个元素就是 16 + 4 + 2

    这样的结构数量必然是 $ log $ ,如果在某个结构查询复杂度是$ Q(n) $ 那么查询复杂度就是$ Q(n)logn $

    重构的复杂度假如是 $ n $ 那么每一个元素最多会被重构 $ logn $ 次,所以,总复杂度是 $ nlogn $

    重构是均摊 $ logn $ 的

    既然支持区间操作,可以对每个区间建个线段树,暴力build线段树也是 $ nlogn $

    复杂度是 $ nlog^2n $ 的

    其实也可以看作建了一棵大的,点数是2的次幂的线段树,当一个点下面的所有叶子都被填了值才把它建出来。本质上是一样的。

    二进制分组怎么删除呢?其实整个序列如果画成一棵树的样子(大概就是版本树之类的?)删除就是往父亲跳,加入就是新加儿子。所以问题本质上就是给你棵树,求某个点到根上的一段的点积的最大值。

    树剖是 $ O(nlog^3n) $ 对询问排序可以去一个log,反正好像不优秀

    题解做法好像是点分

    直接线段树强行搞是不行的,你删除一个插入一个....在一个块的左右反复横跳就挂了

    其实可以搞成随机的,每个点随机一个权值如果比上一个小就合并。

    对于一个块被建出来,如果这个块有东西被删除了,就记个标记表示这个块是坏的。

    查询如果查到一个坏的块(节点)就到左右递归继续查。

    我们希望保证每层只有一个坏的块

    如果结尾一直在最后那个坏块动来动去没啥问题

    但是如果你的结尾移到了前一个块,那么意味着最后面那块被删光了,那么还是只有一个坏块

    但是如果结尾移到了后一个位置,下一个块被建了,那么我们可以直接重构前一个块。

    还不是很明白,想清楚了再继续写吧。。

    这个看起来比较清楚

整体二分

  • 子矩阵查询 kth n 500 q 50000

    直接二分的话,需要查询子矩阵比某个数大的个数

    整体二分,就是拿所有询问一起二分

    我们需要看哪些询问权值是大于 $ \frac{w}{2} $ 的,哪些是小于等于 $ \frac{w}{2} $ 的

    这个比较简单的方法是把小于等于 $ mid $ 的标1,然后前缀和

    然后我们就把询问分成了 $ 0...\frac w 2 $ , $ \frac w 2 + 1 $

    就这样分治下去

    但是每一次分治 $ n^2 $ 肯定是不行的,必须做到每层 $ n^2 $

    每次分治其实我们只需要把 $ l...mid $ 加进去然后做查询

    对于每个询问就是二维数点的问题。

    其实貌似顺次递归来做,就直接是对的了吧。。

    所以对于分治到 $ l,r $ 复杂度就是 $ O(|A|+|Q|logn) $ $ A $ 为这里的点集

    复杂度是 $ (n^2+Q) log^2(n^2) $

  • 单点修改区间 kth

    二分到 $ l,r $ 把一个数字从 $ a $ 到 $ b $ 就是 $ x $ 这个位置 少 $ a $ 多 $ b $

    可以看自己以前的代码吧 $ nlog^2n $的

    ZOJ2112 这题由于空间限制只能整体二分

  • 给 $ l , r $ 的vector 放进去个 k 求 l , r kth

    整体二分就变成区间+了 貌似就是那个 任务查询系统 以前挂了好久的题

  • CF 102354 B

    给定 a , b 两个1...n 排列,求 $ c[k] = MAX_{(i,j)=k}|a_i-b_j| $

    $ c[k] = MAX_{(i.j)=1}|a_{ik}-b_{jk}| $

    其实我们只要求了 $ c[1] $ 问题就解决了

    因为 $ c[k] $ 本质 就是 $ a_k,a_{2k},...,a_{\lfloor\frac n k \rfloor} $ 和 $ b_k,b_{2k},...,b_{\lfloor\frac n k \rfloor} $ 来跑 $ c[1]$

    枚举 $ i $ 就要求最大的 $ b_j , (i,j) = 1 $,因为最大最小是对称的我们求最大的就好了。

    整体二分,分治到 $ (l,r) $,就是知道 $ a_i $ 的最大的值在 l,r 间。

    我们按照 值在 $ mid + 1...r $ 的下标是否存在与当前 $ a $ 互质的把 $ a $ 分成两份分别跑二分下去。

    然后问题就是,统计值在 $ mid + 1 ... r $ 的下表 $ j_t $ 是否存在与某个下标互质。

    对于 $ a_i $ 下标 $ i $,需要统计
    \[ \displaystyle\sum_{j\in A}[(i,j)=1] ​ \]
    莫反一下
    \[ \displaystyle \sum_{j\in A} \sum_{d|(i,j)} \mu(d) \]
    然后我们可以枚举 $ d $ ,给每个 $ d $ 统计一下在 $ A $ 里面的倍数个数,并且把 $ \mu(d) \times cnt $ 放到作为它倍数的 $ i $ 里面。这题可以写一下QWQ

决策单调性

由于没怎么写过决策单调性,可能有很多问题QAQ

就是存在最优的方案决策单调。一般都是打表找的规律。

首先,四边形不等式 $ w(a,d) + w(b,c) \geq w(a,b) + w(c,d) $

假设有 $ i , k , l , j $ , 如果决策不单调意味着 $ i $ 转移到了 $ j $ 而 $ k $ 转移到了 $ l $

如果满足了上面那个式子,相交的两条边优于了包含的边,所以就满足了决策单调性。这大概就是实质了吧?

四边形不等式是 $ O(n^2) $的而不是 $ O(nk) $ 准确的说是 $ O(n(n+k)) $

同时,四边形不等式可以优化二维dp的转移,

满足四边形不等式后,假设 $ dp[l][r] $ 决策点是 $ p[l][r] $,那么
\[ p[l][r-1]\leq p[l][r] \leq p[l+1][r] \]
其实本质就是交错的路径优秀于包含的路径

但是还要注意,虽然四边形不等式可以推出决策单调,但是决策单调不能推出四边形不等式。

  • CF 321 E & 诗人小G (其实没怎么听到题的做法,听了决策单调性优化dp的实现方法)

    下面是几种搞决策单调性的方法

    这里可能还需要再听一下

    $ solve( l , r , p , q ) $ 表示 i 再 $ l , r $ 最优决策是 $ p , q $ 之间

    我们可以先算 $ mid $ 位置的决策点 op 然后,就可以

    $ solve(l,mid,p,op) , solve(mid+1,r,op,q) $

    这样复杂度是 $ O(knlog_2n) $ 这样不容易挂。

    其实也可以二分单调栈。考虑我们如果求出了 $ dp[1] $ 那么后面最优都是从 1 转移过来

    现在求出了 2 , 从 2 转移最优的构成了一个后缀。于是我们可以用单调栈维护每个点可以决定的区间。先从后往前找看能不能整个替代,到达具体区间后再二分。复杂度也是一个 $ log $ 但但是不如前一个好写。

    其实是可以 $ O(nk) $ 的,然而我看不懂 SMAWK

  • CF 868 F

    暴力分治,$ solve( l , r , p , q ) $

    分治下去的时候端点的移动总量是 $ O(r-l+q-p) $ 级别的。

    把指针从 $ p $ 移动到 $ mid $ 并且不断更新每个数字的出现个数,同时不断算 答案并且更新。

    建议看这个学一下再

  • IOI 2013 wombats

    假设是朝右朝下吧,不是很影响 对于 R 这一维建立线段树

    决策是具有单调性的,路径有交叉可以通过调整变短

    如果结束点从上往下走,那么中转点必然也是从上往下走的

    复杂度是 $ O(c^2logclogr) $

    建议看这个

  • IOI 2014 holiday

    首先,肯定不会反复横跳

    然后,结论就是 $ r $ 关于 $ l $ 是决策单调的。

    不太会证,这里引用下钟神的证明:

    设某个区间\([l,r]\)的答案为\(w(l,r)\)

    考虑反证,设\(l\)的最优右端点为\(r\)\(l+1\)的最优右端点为\(r'\),且\(r' < r\)

    那么我们有:
    \[ w(l,r) >w(l,r')\\w(l+1,r') > w(l+1,r) \]
    两式相加得到
    \[ w(l,r) + w(l+1,r') > w(l,r') + w(l+1,r) \]

    \[ w(l,r) - w(l,r') > w(l+1,r) - w(l+1,r') \]
    显然是不成立的,因为上述式子的意义实际上是将\((r',r]\)的元素加入\([l,r']\)或者\([l+1,r']\),带来的额外的贡献。由于加入的元素是相同的,而\([l,r']\)它可以去玩的天数更少,所以
    \[ w(l,r) - w(l,r') \le w(l+1,r) - w(l+1,r') \]

WQS 二分

也就是常说的凸优化

这个东西有关的证明我是都不会的,往往看到 $ O(nk) $ 过不去十有八九就是凸的了。

  • Tree

    我们考虑给所有白色边加权,通过调权值可以让最优策略的白色边个数变化。

    通过二分调整权值使得最优策略正好需要need个白边

什么情况这样二分正确呢?如果代价关于个数的图像是凸的

若 $ f(x) $ 表示选择 $ x $ 个白边(上一个题)的代价

条件就是 $ f(x+1) - f(x) \geq f(x) - f(x-1) $

咋证明,我也不会,只会感性理解QAQ

  • 邮局

    如果权值满足四边形不等式,那 f 一定是凸的。

    所以二分权值,然后用那个单调栈的方法dp一下

    复杂度是 $ O(nlognlogv) $

    --- 开始掉线 ---

    因为轮廓线dp实在不会啊(

    第二天讲了环版本

    还是不会

  • Rikka with K-Match

    没看太懂,后来再康康吧。。。wsl

  • 林克卡特树

    二分,搞个额外代价,虽然不会证明,但是它确实是凸的

    一般 $ O(nk) $ 过不去都是凸的(确信)

  • 一个经典题

    操作A串(添加,删除,修改)使得AB循环同构

    不循环重构

    就是个 $ O(n^2) $ dp

    $ dp[i][j] $ 可以由 $ dp[i-1][j-1] + c_M$ , $ dp[i-1][j] + c_A $ , $ dp[i][j-1]+c_d $ 转移得到

    这个可以看成是平面图上的最段路

    路径上的每个点当成决策点,对起点分治,找 $ 0,\frac m 2 $ 到 $ n , \frac m 2 $ 的路径。

    这个路径上半部分的点只对上面的起点有用,下半部分的点只对下半部分的起点有用

    然后就可以分治下去做

    这大概就是广义的决策单调性 , 不仅可以用于dp

    (这里也很晕)

    循环同构复杂度是 $ n^2logn $ 的

图分治

没听到,起晚咕了,貌似只讲了几分钟,,,有时间回来补吧

树分治

  • 点分治

    最普通的树分治。每次选择重心向下分治就好了。不会超过 $ log $ 层的。

  • 链分治

    三度化

    然后必然可以选择一条边,使得接下来剩下的两个树 $ size $ 最大是原来的 $ \frac 2 3 $ 加一。

    好处在于,链分治后你每次只需要merge两个子树的信息,比较好写。深度也是log的

  • 点分治题目的几个做法

    比如,路径长度不超过 $ k $ 的路径条数

    • 容斥

      每个点单独排序算,容斥减掉

      这个题就是,任意选择两个点长度不超过 $ k $ 减去来自同一子树不超过 $ k $

      可以分别sort一下再总sort,双指针解决问题

    • 如果不能容斥 逐一加入

      每加入一个子树,求这个子树中的 $ v $ 使得 $ dis[v] \leq k - dis[u] $

      可以BIT维护

    • 用哈夫曼树的方法,每次合并最小的两个儿子

      假设合并复杂度是 $ O(S_i+S_j) $

      这样一直合并最小的,复杂度也是对的 带log

      一个位置的合并复杂度是 一个 log总复杂度两个log

  • 问多少点对之间构成路径是合法括号序

    点分治,

    最终要满足的必然是 $ u $ 到 $ r $ 的路径只剩下了一些左括号了, $ r $ 到 $ v $ 只剩下一些右括号了。

  • 问距离为素数的点对(距离为 1 ~ n ) 的点对

    还是考虑是否经过分治中心

    每个子树写成生成函数 $ p_i $ 的形式,$ a_k $ 表示有多少个深度为 $ k $ 的

    要求的是 $ \displaystyle \sum_{i\neq j} p_ip_j $

    可以 $ \frac{(\sum p_i)^2-\sum p_i^2}{2} $ 容斥做

  • 树上背包

    给定一棵树,每个位置都有容量和价值,选一个联通子树使得体积和小于等于 $ V $ 重量和最大。

    如果确定了选根,那么你总是需要合并两个背包然后人就没了

    先按照 DFS 序排序后,子树总是一段连续区间

    $ dp[i][j] $ 考虑 $ i ... n $ 这段物品,考虑一个物品选了,在下个物品继续选择 $ dp[i+1][j-v_i] + w_i $

    如果一个物品没选,必须把整个子树跳过 $ dp[r_i][j] $

    这样可以处理根一定被选择的答案,复杂度是 $ O(nV) $

    根不一定被选,所以套一层点分质就对了。

    复杂度是 $ O(nVlog) $

  • 一棵树,每个点还是有代价和权值,选择一些物品,使得它们不在树上相邻。

    求出这样的东西的背包

    $ n \leq 100 , V \leq 10000 $

    复杂度是 $ n^2 V $

    考虑点分,按照点分治选择根的顺序标号,考虑 $ dp[i][j][S] $ 前 $ i $ 个物品,容量和是 $ j $ ,前面每个物品选没选是 $ S $ (集合)这样算法复杂度是 $ nV2^n $

    但是实际上前一个子树不会影响后一个子树,所以我们不需要知道每个点是否被选只需要记录点分中心是否被选。所以 $ S $ 只需要记录这个点到根的路径是否被选,$ S $ 是 $ 2^{log} $,复杂度没问题。

    HDU6556 可以写一下。

点分树

点分治过程中形成的树,可以方便处理带修改的问题。修改的处理往往是从一个点向上跳(只有 log 层)

  • BZOJ 3730

    对于所有 $ x,r $ 求 $ \displaystyle \sum _{dis(v,x)\leq r} b_v $

    点分,分 $ x $ 到 $ v $ 的路径是否经过中心讨论。

    考虑跨过中心的话,

    现在要求的其实是 $ dis(v,T) \leq r - d_x $ 的点 - 在 $ x $ 子树中 $ dis(v,T) \leq r-d_x $ 的点。

    对于每个 $ T $ 记录小于等于 $ k $ 的权值和。

    怎么加修改呢?我们对于每个点都仍然记录了小于等于 $ k $ 的权值和。我们可以用一个大小为 $ O(size) $ 的BIT记录这个,这样小于等于 $ k $ 就是前缀查询。

    如果一个点被修改了,到它的所有点分中心都要被修改。

    这些点分中心分别单点改就好了。

  • Qtree 4 / zjoi Hide

    边分治可能要简单一点,因为每次只用处理两个部分

    先三度化,然后选择一个边切掉,考虑两个黑点是否经过分治边。

    其实就是这个边两端的最远距离。分治的时候分别记录边两棵子树所有黑点到根的距离

    由于支持点修改,可以每个分治中心搞个 multiset 维护

    外部再开个multiset表示每个分治中心对答案的贡献。 $ nlog^2n $

    其实有单log做法的

    可以先把欧拉序写出来,然后 $ q $ $ p $ 的距离就是 $ dep[q]+dep[v]-2\min{dep[r]} ,q\leq r \leq p $

    直径就是要加个 $ max $

    所以就是 $ \max{dep[p]+dep[q]-2dep[r]},q\leq r\leq p $

    所以其实就是要找给定欧拉序,整个序列要选择三个位置,第一、三个位置贡献是1,第二个是-2,使得权值尽量大。线段树记录一下 $ p $ 在这个区间,$ pr $ 都在这个区间,$ r $ 在这个区间...这些东西。然后这个是可以 pushup 的

  • 给定一个树,每个点有权值 $ a_i $ ,修改 $ a_i $ ,查询 $ \min_u \sum a_i dis(i,u) $

    每个点度数不超过20(其实没有貌似也可以做,三度化一下嘛)

    当这个东西取到最小, $ u $ 必然是重心。如果是重心每个子树的和都不会超过 $ \frac {\sum a_i} 2 $。因为如果不是重心,我们明显可以往多于 $ \frac S 2 $ 的儿子走,这样一定可以让答案变小。

    所以要求的其实是一个带权重心。

    单独求这个其实很简单,如果所有子树都不超过一半就是这个点,否则往多于一半的儿子走就好了。

    建立点分树,我们递归下去后一个子树是这个递归下去的子树的大小,但是我们需要维护的是这个子树在全局意义下的大小。如果我们当前在 $ T_1 $ 我们要进入 $ T_2 $ 我们就把 $ T_1 $ 的重量全部挂到 $ T_2 $ 的某一个分支。就是把对应的子树的权值加 $ w $ ,做完了再减掉就好了。

  • CF 566C

    给定i一棵树 $ \min_x \sum dis(i,x)^{1.5} $

    $ f(x) = x^{1.5} $ 是凸函数 加几次都是凸函数,所以 $ G(x) = \sum d(x,i) $ 也是凸函数

    还是找一个点分治的重心,看它往哪边跳会变大。必然只有往一个方向走会变小,因为如果有两个方向走可以变小,那么一定不是凸函数。

    如何找到往哪个方向会变小?这里做法是求导,假设 第 $ i $ 个子树的根是 $ rt_i $ 这个子树内所有点的导数的和是 $ p_i $ 那么往这个方面走是 $ \sum p_j - 2p_i $,需要找到唯一一个方向,使得导数是负数的方向走

    具体看 这个 吧

  • 动态点分治 紫荆花之恋

    添加叶子,维护点分树的结构

    点分树的结构是很容易变的啊(添加叶子时)

    所以我们维护的不是严格的点分树,而是每个点的儿子要小于等于 $ \alpha n $ 的,$ \alpha $ 一般取 0.8~0.9

    这样整个树也是一个log级别的

    但是我们一直往一边插入节点,明显会变得不平衡

    所以如果某个子树不平衡了,dfs这个子树并且重构一边就好了,其实和替罪羊的pia操作一样

    复杂度分析也是和替罪羊一样的

  • 重量平衡树 带插入区间 kth

    (从分治与分块自然过渡到数据结构?)

    重量平衡树要做的事情是,一个点插入影响的子树只有$ O(logn) $ 的(不管是期望,严格之类的)所以splay修改的子树大小是 $ O(n) $ 的。就是一个点插入后需要更新的个数是 log 的

    只有这样可以方便的套其他树

    重量平衡树: Treap,替罪羊

    做这个大概就是替罪羊套 线段树

    应用:有个序列,可以在log的复杂度插入,O1比较两个数哪个在前面

    对于每个点我们维护一个区间,比如根节点是0,1,根的左儿子是 $ 0,0.5 $ 右儿子是 $ 0.5,1 $

    这样的话直接插入可能导致一些问题,可能精度不够或者退化 $ n^2 $

    所以需要重量平衡树比如替罪羊的同构

分块

分块实质上可以看成一个 $ \sqrt n $ 叉树

  • 引入:区间+区间求和

    分块:大小 sqrt n 分成若干块 整段打标记,零散暴力

    区间求和就一样

    $ O(m\sqrt n) $

  • 区间+ 区间小于 x 的个数

    还是先分块 对于整块+ 就打标记,零散块直接+

    查询两头暴力 for ,块内维护了有序的序列,一个 log

    块大小设 $\sqrt{nlogn} $

  • 区间 + 查询区间 kth

    外面再套个二分。

    直接做的话

    查询,是 $ \frac n T log^2n + Tlogn $

    修改,是 $ \frac n T + T $

    直接做是 $ \sqrt n log^{1.5} $ 不太行

    可以把 $ T logn $ 这部分优化成 $ T + logn $ 因为可以先拿零散块归并一下

    这样就可以 $ T = \sqrt n logn $

  • 根号平衡!

    优化复杂度利器

    • $ O(1) $ 修改, $ O(\sqrt n) $ 求和

      直接分块做

    • $ O(\sqrt n) $ 修改,$ O(1)$ 求和

      每个块内部维护前缀和,维护整块前缀和

      反正类似这个的问题都是可以根号平衡的

    • $ O(1) $ 插入 $ O(\sqrt n) $ 查询 kth

      值域分块

      查询 kth 貌似变成了一个找前缀和大于 k 的问题。遍历块即可。 \(O(\sqrt n)\)

    • $ O(\sqrt n) $ 插入 $ O(1) $ 查询 kth

      数字从小到大排序,每块大小都是 $ T $ 级别的

      插入一个位置,对后面每个块都是前面插入一个,从后面pop一个

      其实就是块状链表吧?

      查询 kth 就直接查就好了。因为每个块大小固定

  • 给定 $ n $ 个数,和 $ m $ 个函数,每个函数是 $ l_i,r_i $ 数的和

    每次询问:

    1 把第x个数字变成y

    2 求 x...y 函数的和

    把函数分块,维护每块函数的和,然后就是求两头额外函数的和。

    预处理每个数字对一个块的贡献是多少

    修改是 $ O(\sqrt n) $ 的。

    用前面那个平衡的方法,是 $ O(m\sqrt n) $ 的

莫队

做那种可以快速支持插入删除,但是完全不能支持信息合并的问题

当然有些时候也不可以删除,这种情况是回滚莫队

  • 引入:区间内所有数字出现次数的平方和

    插入删除明显 $ O(1) $

    做法是对所有询问分个块(按照 $ T $ )

    每块的询问按照左端点所在的块,右端点从左往右走

    这样看起来复杂度就很 $ \sqrt n $

    复杂度就是 $ O( n\sqrt m ) $ 我也不知道为什么。

    块大小 $ O(\frac {n}{\sqrt m}) $

    一个优化

    奇数块从小到达,偶数从大到小

    右端点是来回跳的,快一些。

    (科学研究表明)最快 的 块大小$ \frac n {\sqrt{\frac 2 3 m}} $

  • 查询区间值在 $ [a,b] $ 内的不同数个数

    跑莫队维护树状数组,复杂度是带log的根号

    我们可以运用添加 $ O(1) $ 查询 $ O(\sqrt n) $ 的根号平衡,复杂度是一个根号。

  • BZOJ 3920

    给定一个序列,查询区间中出现次数 $ k_1 $ 小的数里面 $ k_2 $ 小的数

    先离散化,比如 $ x $ 出现了 $ cnt_x $ 次,把$ (1,x),(2,x),...,(c,x) $ 离散化,每次加一个数进来,就是加一个 $ (c+1,x) $ 进来。

    查询就是利用前面那个修改 $ O(1) $ 查询 $ O(\sqrt n ) $ kth 的根号平衡

  • LOJ 2874

    一个数的权值是它出现的次数 * 数值大小,查询区间中最大的权值

    对于所有数字 $ x $ 你就把 $ x , 2x , 3x, ... ,cnt x $ 离散化

    然后问题就变成了你要支持维护最大值的莫队

    按照权值分块找最大值就可以了。

  • 区间逆序对

    最简单的做法:莫队树状数组,带 log

    如何去掉log?

    我们要做 $ O(n\sqrt m ) $ 次查询 $ l , r $ 小于等于 $ x $ 有多少个

    如果可以离线,这个就可以做

    就是我们可以块状树的方法去做,但是这个查询的区间是在改变的

    最暴力的方法是把那个分块结构可持久化

    每次做就把修改过的块复制一遍,再把所有块之间的前缀和给复制一遍

    但是这个方法也不优秀 常数很大空间也不优秀

    因为数组开大了cache读取也很慢

    所以有另一种方法——

  • 二次离线莫队

    [a,b] [c,d]表示 \(x \in [a,b], y\in [c,d] , a_x > a_y\)的数量

    从 $ l , r $ 移动到 $ l , r' $,增加量是

    $ \sum_{i=r}^{r'} [l,i-1][i,i] $

    把 $ l,i-1 $ 拆成两个前缀的-

    增量是 $ \sum_{i=r+1}^{r'} [1,i-1][i,i] - [1,l-1][i,i] $

    左边的东西只跟 $ i $ 有关,右边那个加起来是 $ [1,l-1][r+1,r'] $

    现在我们相当于有了 $ m $ 个这样的询问

    对于这个东西我们再次做一次离线

    按照 $ l $ 排序,一个一个数字加进去,然后我们就有询问,就可以 for 一下 $ r+1,r' $ 来做

    这就是第二次离线

    很巧妙 啊QAQ

  • 树上莫队

    解决一些树上查询的问题

    比如一条路径有多少种不同的颜色

    怎样写比较简单呢?

    用欧拉序,把每个东西进栈写一次出栈写一次

    对于 A 点 和 B 点,找到它们在序列中第一次出现的位置,然后把它们第一次出现的位置之间的东西拿出来

    把拿出来的数出现了两次的东西都去掉,再把端点和 LCA 胡上去

    现在得到的就是这条路径上的东西

    这个东西复杂度就是序列莫队(其实就是序列莫队)

    就是一个把树上问题转移到链上的做法

  • 带修莫队

    莫队上面会有一些修改操作

    我们把时间当成一维,两个修改的距离就是三个维度都移动,复杂度是 $ O(n^{\frac 5 3}) $

    块大小大概是 $ n^{\frac 2 3} $

    先按照 $ l $ 所在块,在用 $ r $ 所在块,再用 $ t $ 排序

    最坏复杂度 $ n^\frac 5 3$

    证明:我不会

  • Codechef QCHEF

    求区间最大的 $ |x-y| $ 使得 $ a_x = a_y $

    回滚莫队,就是这种不好删除比较好插入的题。我不太会,上课过的有点快,先咕一会

  • CF 765 F (由于块太毒瘤突然插入的一个线段树题)

    查询区间绝对值差的最小值

    $ l , r $ 间的 $|a_i-b_i| $ 的最小值

    扫右端点维护左端点的答案

    分大于 $ a_r $ 和小于讨论

    找到靠后第一个比 $ a_r $ 大的东西,可以用 $ a_j - a_r $ 更新所有 $ 1 \leq l \leq j $ 的答案

    然后找到一个小于等于这两个数平均数的元素

    因为如果比这两个平均数大, $ a_j - a_k $ 来得更小,$ a_r $ 不会影响答案

    同理一直这样找小于等于平均数的数字

    这个可以对值域开一个线段树,每个权值记录它最后出现的位置,每次要查询的是 $ a_i $ 前面第一个比 $ a_i $ 大的,就是 $ a_i+1,+\infin $ 最大的值,然后就变成查询 $ a_i+1,\frac{a_i+a_j}{2} $ 的最靠后来更新。复杂度是 $ O(nlognlogv) $

    据说有单log或者双log带修不会

  • 经典问题

    点权+,查询 $ x $ 相邻的点权和

    按照度数 是否大于 $ \sqrt m $ 来分类做。

    每个点记录下它的小邻居的和,修改小点直接给出去的边修改。

    修改大点,直接修改

    查询 查大点就好了

    复杂度是 根号

  • 树,点权,多次查询,每次给 x y k 求从 x 开始每次跳k个节点到 y 所经过节点的和

    按照 $ k $ 与根号关系,

    • 大于根号就直接跳,我们可以树剖一下,对于每个链我们记录一下,如果在一个重链上跳是不会有log的 , 长链剖分就没log了

      或者我们对于每个点记录它的一级,二级,...sqrt 级祖先,和sqrt , 2sqrt...级祖先

    • 小于根号就是求 x 到 y 路上 深度 % k 为 r 的点权和

      x 到根的 深度膜k为r的点权和 dfs的时候拿个数组记录一下膜k为r的点权和为多少

      (其实对k很大也可以离线来做的)

      复杂度是可以线性的

  • YNOI 2015 此时此刻的光辉

    查询区间乘积的约数个数

    暴力莫队,对每个因子记下出现次数,会TLE

    本质不同的因子个数不是log个,是 log/loglog 但是还是T了

    每个数的大于 $ v^{\frac 1 3} $ 的质因数个数只有2个,小于等于 $ v^\frac 1 3 $ 的质数只有 $ v^ \frac 1 3log $

    v = 1e9小于1000的质因数个数只有168个

    维护感觉类似寿司晚宴

树分块

  • COT 2

    树,点权,强制在线,查链颜色数

    随机打 $ \sqrt n $ 个点,可以认为一个点到它上一个被选中的点的距离期望是 $ \sqrt n $ 的。

    或者用深度是 $ \sqrt n $ 的倍数并且它往下的深度是大于根号的点

    这样选择可以保证每个点往上 $ 2\sqrt n $ 必然可以碰到关键点。

    我们先预处理出关键点两两间的答案

    预处理是从每个关键点dfs就知道了关键点两两答案。

    现在就是看某个颜色从某个点到根的出现次数

    这个比较暴力好想的做法是主席树,记录某个颜色的出现次数,复杂度是一个log

    但是其实可以套用之前的分块结构,修改 $ n^\frac 1 2 $ 查询 $ O(1) $ 的块状树,可持久化一下,这样就可以做到 $ O(1) $ 了虽然空间有点菜是 $ n\sqrt n $

你可能感兴趣的:(分治与分块)