省选06. 分治

CF1442D Sum

\(dp(i,j)\) 表示前 \(i\) 个数组选 \(j\) 个元素的最大值。

\[dp(i,j)=\max_{k=0}^jdp(i-1,k)+sum(i,k) \]

因为数组内的元素单调不降,因此有一个结论,只有一个数组会选一部分的元素,其它数组要么不选,要么选完。

于是可以考虑维护一个前缀的背包和一个后缀的背包,对每个数组钦定它只选部分,并枚举它选几个元素,然后将前缀背包和后缀背包合并。

但这样做的复杂度为 \(O(nk^2)\),瓶颈在于两个背包的合并复杂度达到了 \(O(k^2)\)

仔细思考后可以发现,往背包中加入一个元素较容易,复杂度为 \(O(k)\),但合并较为困难,复杂度为 \(O(k^2)\),因此可以考虑使用与线段树分治类似的思想,只加入不合并,递归进入一个区间时将另一个区间的元素加入背包,递归退出时撤销操作。时间复杂度可以达到 \(O(nk\log n)\)

CF1100F Ivan and Burgers

线段树暴力维护时间复杂度为 \(O(n\log^3n)\),如果换成猫树,复杂度可降为 \(O(n\log^2 n)\)

考虑离线,按照 \(r\) 从小到大排序,线性基插入时对每一位维护插入元素编号的最大值。

P4585 [FJOI2015]火星商店问题

线段树分治所解决的问题可以看成一个二维问题,一维是时间,一维是空间。

主要特点在于修改和询问在某一维上一个是区间,一个是单点。

当然,这一维大都是时间。

本题的询问在时间上是区间,但查询在时间上是单点,且支持离线,因此可以用线段树分治在 \(O(n\log^2n)\) 解决。

CF813F Bipartite Checking

线段树分治裸题,重点在于如何维护一个二分图。

一个图为二分图的条件是点数大于等于 \(2\) 且不存在奇环。

考虑如何维护二分图,这可以使用带权并查集来维护。

假设当前连通的集合只是一棵生成树,连接一条边后形成环。

如果是奇环,那么无论以后怎么连它都不可能是二分图,标记一下。

如果是偶环,那么不用管这条边,因为如果后面的边能与这条边形成奇环就一定能与生成树的边形成奇环。

因此只需要维护这个图的生成树即可。

定义 \(dis(x)\),表示并查集上一个点到它父亲的奇偶性,\(d(x,y)\) 表示原树上两点距离的奇偶性。

如果 \((x,y)\) 连边,先判断是否形成环。

如果还是一棵树,考虑合并。

定义 \(px\)\(py\),分别表示 \(x\)\(y\) 所在的代表元,假设将 \(x\) 所在的集合并到 \(y\) 所在的集合上。

那么,令 \(dis(px)=d(x,px)\oplus d(y,py)\oplus 1\) 即可。

考虑证明这样做的正确性。

对于新生成树上的路径 \(u\rightarrow v\),分三种情况讨论。

  • 如果 \(u\)\(v\) 原本在 \(x\) 所在的连通块内,原本 \(d(u,v)=d(u,px)\oplus d(v,px)\),现在 \(d(u,v)=d(u,px)\oplus d(v,px)\oplus d(px,py)\oplus d(px,py)=d(u,px)\oplus d(v,px)\)

    成立。

  • 如果 \(u\)\(v\) 原本在 \(x\) 所在的连通块内,证明同上。

  • 如果 \(u\)\(v\) 原本分别在 \(x\)\(y\) 所在的连通块内。

    原本 \(d(u,v)=d(u,x)\oplus d(v,y)\oplus 1=d(u,px)\oplus d(x,px)\oplus d(v,py)\oplus d(y,py)\oplus 1\)

    现在 \(d(u,v)=d(u,py)\oplus d(v,py)=d(u,px)\oplus d(v,py)\oplus dis(px)\)

    \(dis(px)=d(x,px)\oplus d(v,py)\oplus 1\) 即可。

这启示我们在使用并查集维护路径信息的时候都可以分如上三种情况讨论。

P3733 [HAOI2017]八纵八横

线性基 + 线段树合并。

使用上一题的结论用并查集维护连通块,合并的时候根据线性基的性质任选一个环即可。

注意回撤时的复杂度,栈里面记录线性基被修改的位置即可。

P5416 [CTSC2016]时空旅行

对于一个星球 \(i\)\(y_i\)\(z_i\) 是没有用的。

于是对于一次查询 \(x_0\),答案为 \(\min_{i} (x_i-x_0)^2+c_i\)

化简一下就是 \(-2x_ix_0+x_i^2+c_i+x_0^2\)

于是可以线段树分治将星球放到时空上,查询就相当于是对所有存在的直线,询问某个点的最优值,可以用李超线段树维护。

但使用李超线段树撤销操作占用空间大,因此考虑换一种思路。

不动态加直线,改成动态加点,即令 \(2x_0x_i+b=x_i^2+c_i\),最后再加上 \(x_0^2\),每次加入一个点 \((x_i,x_i^2+c_i)\),用一条斜率为 \(2x_0\) 的直线去切这些点,使截距最小。这相当于维护一个下凸壳,每次找到第一个斜率大于 \(2x_0\) 的直线,它下面的点即为最优解的取值。

P2487 [SDOI2011]拦截导弹

CDQ 分治优化 dp 的基础应用,详见 OI-Wiki。

\(f_1(i)\) 表示以 \(i\) 结尾的最长不降子序列的长度。

\[f_1(i)=\max_{j<i,a_j\geq a_i,b_j \geq b_i}f_1(j)+1 \]

直接转移是 \(O(n^2)\),因此使用 CDQ 分治。

算法流程如下:

  • 递归区间 \([l,mid]\)
  • 计算 \([l,mid]\longrightarrow[mid+1,r]\)
  • 递归区间 \([mid+1,r]\)

按照如上顺序执行是为了保证 dp 转移的有序性,相当于是在 CDQ 分治树上中序遍历。

下面考虑如何计算 \([l,mid]\longrightarrow[mid+1,r]\)

\([l,mid]\)\([mid+1,r]\) 按照 \(a\) 从大到小排序(注意,最后递归区间 \([mid+1,r]\) 之前要按照下标重新排序,因为还未处理那段区间)。

开一棵以 \(b\) 为下标的树状数组,每次查询前缀最大值即可。

以上是第一问,下面思考第二问。

再记 \(g_1(i)\) 表示以 \(i\) 结尾的最长不降子序列的方案数。

对于树状数组的每一个点,记录一个二元组 \((f,g)\),分别表示长度和方案数,这可以直接合并。

另外还需要处理一下以 \(i\) 开始的子序列,长度和方案数分别为 \(f_2(i)\)\(g_2(i)\)

那么最后每个满足条件的点的总方案数为 \(g_1(i)g_2(i)\)

综上,总时间复杂度为 \(O(n\log^2 n)\)

P4027 [NOI2007] 货币兑换

\(f(i)\) 表示第 \(i\) 天能够拥有的最多钱数,\(cnta(i)\) 表示第 \(i\) 天使用 \(f(i)\) 元能够兑换的 A 券数量,\(cntb(i)\) 表示第 \(i\) 天使用 \(f(i)\) 元能够兑换的 B 券数量。\(cnta(i)=\frac{f(i)rate(i)}{a(i)rate(i)+b(i)}\)\(cntb(i)=\frac{f(i)}{a(i)rate(i)+b(i)}\)

  • \(i\) 天不卖 \(f(i)=f(i-1)\)

  • \(i\) 天卖

    \[\begin{aligned} f(i) &=\max_{0<j<i}cnta(j)a(i)+cntb(j)b(i)\\ &=\max_{0<j<i}b(i)\left(\frac{a(i)}{b(i)}cnta(j)+cntb(j)\right) \end{aligned} \]

所以

\[cntb(j)=\frac{a(i)}{b(i)}({-cnta(j)})+\frac{f(i)}{b(i)} \]

这可以斜率优化,但发现横坐标没有单调性,因此使用 CDQ 斜率优化 dp。

流程如下:

  • 递归区间 \([l,mid]\)
  • \([l,mid]\) 的点按横坐标排序,\([mid+1,r]\) 的点按斜率排序,使用单调队列维护(双指针)。
  • 递归区间 \([mid+1,r]\)

可以发现,CDQ 分治优化 dp 的题目本质都是能够快速计算 \([l,mid]\)\([mid+1,r]\) 的贡献。

因此,不只是 dp 的题目,其它能够转化成区间对区间的贡献,且这种贡献能够通过某种方法高效计算的题目也能使用 CDQ 分治。

P4390 [BOI2007]Mokia 摩基亚

转化成三维偏序问题,设每个点的坐标为一个三元组 \((x,y,t)\),表示在 \(t\) 时刻,坐标 \((x,y)\),问题就转化为三维空间上一定范围内点的权值和,直接使用 CDQ 分治即可。

P4093 [HEOI2016/TJOI2016]序列

\(f(i)\) 表示以 \(i\) 结尾的满足条件的最长不降子序列的长度。

\[f(i)=\max_{0<j<i} f(j)+1 \]

且必须满足 \(maxval(j)\leq a(i)\)\(a(j)\leq minval(i)\)

直接使用 CDQ 分治优化 dp 即可。

P3157 [CQOI2011]动态逆序对

先将初始情况的逆序对数计算处理,然后计算每次删数的影响。

设第 \(i\) 次删除位置为 \(pos(i)\),第 \(i\) 个位置的值在第 \(t(i)\) 次被删去,那么第 \(i\) 次删除后逆序对减少的条件是

\[\begin{cases} j<pos(i)\\ a(j)>a(pos(i))\\ t(j)>t(pos(i)) \end{cases} \]

\[\begin{cases} j>pos(i)\\ a(j)<a(pos(i))\\ t(j)>t(pos(i)) \end{cases} \]

直接离线下来 CDQ 分治即可。

P3206 [HNOI2010]城市建设

加深了我对 CDQ 分治的理解。

一般的 CDQ 分治题目比较套路,都是计算 \([l,mid]\)\([mid+1,r]\),再考虑一下它们之间的影响。

而这道题目不是,这道题目定义分治区间 \([l,r]\) 表示将修改区间 \([l,r]\) 的边设为动态边,其它边为静态边。

每次可以将必然在最小生成树内的静态边加入,必然不在最小生成树内的静态边删去。

先递归并修改 \([l,mid]\) 再递归 \([mid+1,r]\),左区间对右区间有影响,但并没有单独计算这一影响,只是按照时间顺序递归到叶子,因此也可以叫 CDQ 分治。

P4690 [Ynoi2016] 镜中的昆虫

\(pre(i)\) 表示 \(i\) 左边第一个与 \(i\) 的颜色相同的点的位置,若左边没有颜色,那么 \(pre(i)=0\)

于是可以使用珂朵莉树维护连续段,可以证明 \(pre(i)\) 总数是 \(O(n)\) 的。

于是修改可以看成四元组 \(U(pos,pre,t,k)\),询问可以看成四元组 \(Q(l,r,t,id)\)

于是产生值为 \(k\) 的贡献的条件是

\[\begin{cases} Q(l)\leq U(l)\leq Q(r)\\ U(r)<Q(l)\\ U(t)\leq Q(t) \end{cases} \]

使用 CDQ 分治即可。

P1527 [国家集训队]矩阵乘法

整体二分,二分一个答案 \(mid\),将 \(l\)\(mid\) 的数加入树状数组,对当前的询问区间进行判定,得到新的询问区间。

复杂度正确的原因在于值域线段树的每一层,每一个值域只会被加入树状数组一次。

P3242 [HNOI2015] 接水果

考虑路径 \((x,y)\) 被路径 \((u,v)\) 包含的条件。

不妨 \(L(x)<L(y),L(u)<L(v)\)

  • \(x=LCA(x,y)\)

    \(dfn(u)\in[1,dfn(z)-1]\)\(dfn(u)\in [dfn(z)+siz(z),n]\)\(dfn(v)\in[dfn(y),dfn(y)+siz(y)-1]\)

    其中 \(z\)\(y\) 往上跳,最接近 \(x\)\(x\) 的儿子。

  • \(x\neq LCA(x,y)\)

    \(dfn(u)\in[dfn(x),dfn(x)+siz(x)-1]\)\(dfn(v)\in[dfn(y),dfn(y)+siz(y)-1]\)

于是可以考虑对每个 \((u,v)\) 二分答案,统计权值 \(\leq mid\) 的点数。

相当于是要在二维平面上区间加单点查,差分后为单点加区间查。

将询问和修改一起按照某一维排序后可以扫描线 + 树状数组解决。

因此总复杂度为 \(O(n\log^2 n)\)

P7424 [THUPC2017] 天天爱射击

整体二分一下木板碎掉的时间,使用树状数组维护单点加,区间查即可。

CF868F Yet Another Minimization Problem

\(dp(i,j)\) 表示将长度为 \(i\) 的序列分成 \(j\) 个子段的最小代价。

\[dp(i,j)=\min_{k<i}dp(k,j-1)+w(k+1,i) \]

决策点具有单调性,因此可以考虑使用分治优化。

对于递归的每一层,枚举决策点复杂度为 \(O(n)\),求解 \(w\)\(O(n)\),总共有 \(\log n\) 层,因此转移一次复杂度为 \(O(n\log n)\)

总共要转移 \(k\) 次,总复杂度为 \(O(kn\log n)\)

CF940F Machine Learning

带修莫队。

将值域离散化,记录每种值出现的次数,以及每种次数出现的次数。

\(mex\) 的时候暴力即可,因为求 \(mex\) 的复杂度为 \(O(\sqrt{n})\),而带修莫队的复杂度为 \(O(n^{\frac{5}{3}})\)

因此总时间复杂的为 \(O(n^{\frac{5}{3}})\)

P3245 [HNOI2016]大数

\(sum(i)\) 表示以 \(i\) 结尾的前缀模 \(p\) 的结果。

一段子串 \([l,r]\)\(p\)\(0\) 的条件是 \(sum(r)-sum(l-1)\times10^{r-l+1}\equiv 0\pmod{p}\)

\(p\)\(10\) 互质时,需满足 \(\frac{sum(r)}{10^r}\equiv \frac{sum(l-1)}{10^{l-1}}\pmod{p}\),即同种颜色的点对数。

\(p\)\(10\) 不互质时,开一个桶记录余数即可。

P4689 [Ynoi2016] 这是我自己的发明

对于每个询问,可以根据点与根的关系拆成很多个区间。

\(ans(l1,r1,l2,r2)\) 为一个点在区间 \([l1,r1]\),另一个点在 \([l2,r2]\) 的答案。

\[ans(l1,r1,l2,r2)=ans(1,r1,1,r2)-ans(1,l1-1,1,r2)-ans(1,r1,1,l2-1)+ans(1,l1-1,1,l2-1) \]

CF620F Xors on Segments

\(sum(i)=1\oplus 2\oplus 3\cdots \oplus i\)

\(f(l,r)=sum(r)\oplus sum(l-1)\)

\(f(a(x),a(y))=sum(a(y))\oplus sum(a(y)-1)\)

对区间 \([l,r]\) 的每一个 \(i\),trie 树上插入 \(a(i)-1\),查询 \(a(i)\) 与哪个元素异或最大。

P5047 [Ynoi2019 模拟赛] Yuno loves sqrt technology II

\(f(x,[l,r])\) 表示 \([l,r]\) 中比 \(x\) 大的数的个数。

\(g(x,[l,r])\) 表示 \([l,r]\) 中比 \(x\) 小的数的个数。

\[(l,r+1):f(r+1,[l,r]) \]

\[(l,r-1):-f(r,[l,r-1]) \]

\[(l-1,r):g(l-1,[l,r]) \]

\[(l+1,r):-g(l,[l+1,r]) \]

P5398 [Ynoi2018] GOSICK

\(f(x,[l,r])\) 表示 \([l,r]\)\(a(x)\) 的倍数个数。

\(g(x,[l,r])\) 表示 \([l,r]\)\(a(x)\) 的约数个数。

\[(l,r+1):f(r+1,[l,r])+g(r+1,[l,r]) \]

\[(l,r-1):-f(r,[l,r-1])-g(r,[l,r-1]) \]

\[(l-1,r):f(l-1,[l,r])+g(l-1,[l,r]) \]

\[(l+1,r):-f(l,[l+1,r])-g(l,[l+1,r]) \]

posted @ 2022-12-24 09:17  top_tree  阅读(51)  评论(0)    收藏  举报