Loading

最值分治生成树

全文5368k。

额...只不过是因为刷题赛里出现了两道笛卡尔树,所以特意从新拿出来审视了一遍。

今天晚上要 Hello 2023,所以可能更没有时间补那道多项式了qwq。

至于线段树,那又只能明天学了/bai

笛卡尔树

定义:满足堆性质的二叉搜索树,也就是常用的 Treap。

性质:中序遍历是原序列;父亲的权值比儿子小(以小根堆为例)

如果这是一个全序关系,那么这个笛卡尔树是唯一的。

建树:

笛卡尔树可以通过单调栈 \(O(n)\) 构建。具体伪代码如下:

for (int i = 1; i <= n; i++)
{
    while (top > 0 && a[stk[top]] > a[i]) ls[i] = stk[top--];
    if (top) rs[stk[top]] = i;
    stk[++top] = i;
}

例 1 洛谷P5854【模板】笛卡尔树

https://www.luogu.com.cn/problem/P5854

给定一个 \(1 \sim n\) 的排列 \(p\),构建其笛卡尔树。

模板题。

随机笛卡尔树的树高是 \(O(\log n)\) 的,其实是调和级数。

例 2 AGC028B Removing Blocks

https://www.luogu.com.cn/problem/AT_agc028_b

\(N\) 个数,每个数有一个全会 \(A_i\)。进行 \(N\) 次操作,每次操作选择一个数删掉,代价是所有和其连通的没被删掉的数的权值和,求所有 \(N!\) 种删数方法的代价和。

考虑对删除序列建小根堆笛卡尔树,那么每个点的贡献即为子树中 \(a\) 的和。转换为每个点贡献是 \(a_i\times dep_i\),那么所求即为期望深度。根据前几天平衡树的那个证明,可以发现这个期望深度应该是 \(\sum_{j=1}^{x-1}\frac{1}{x-j+1}+\sum_{j=x+1}^{n}\frac{1}{j-x+1}+1=H(i)+H(n-i+1)-1\)\(H(n)=\sum_{i=1}^{n}\frac{1}{n}\)。这样就可以 \(O(n)\) 计算了。

例 3 RMQ Similar Sequence

Petrozavodsk Summer 2018. Day 4. Xi Lin Contest

http://qoj.ac/problem/242

给定序列 A,序列 B 的每个元素在 \([0,1]\) 之内随机(实数),B 的价值是,当 B 和 A 的笛卡尔树同构时为元素和,否则是 \(0\)。求 B 的价值的期望。定义值相同时排在前面的更大。

由于是在实数中随机,所以两个数相等的概率是 \(0\),那么可以假设 B 是一个排列,一个排列与 A 的笛卡尔树同构,其实就是拓扑序相同,那么 B 的个数就可以算出了。即为 \(\frac{n!}{\prod sz_i}\)\([0,1]\) 中随机一个数的期望是 \(\frac{1}{2}\),所以 \(n\) 个数的和的期望就是 \(\frac{n}{2}\) 用这个值去乘上排列的个数即可得到答案。
code

有关深度的计数,以及一些和深度有关的结论。

例 4 CF1220F Gardener Alex

https://codeforces.com/problemset/problem/1220/F

给定长度为 \(n\) 的排列,可以将前 \(i\) 个元素移动到最后,所有可能的排列的小根笛卡尔树的最大深度的最小值。

考虑对于两个位置 \(i,j\),什么时候 \(j\)\(i\) 的祖先,也就是 \(\min_{\min(i,j)\le k\le \max(i,j)}p_k=p_{j}\) 的时候。那么这道题,我们就可以模拟移动的过程,每次找到第一个大于他的位置,然后前面的位置都可能被贡献到,用一个线段树来维护即可。code

例 5 USACO19DEC Tree Depth P

https://www.luogu.com.cn/problem/P5853

对每个数求出所有逆序对数是 \(k\) 的长度为 \(n\) 的排列的笛卡尔树上的深度和,深度定义为根到它的点数。

有一个算逆序对的方法,是按顺序从小到大加入,那么这样每次可以贡献的逆序对数刚好从 \(0\)\(i\),那么就相当于卷上一个 \(\sum_{j=0}^{i-1}x^j\) 这样的 OGF。最后答案就是 \([x^{k}]\prod_{i=1}^{n} \frac{1-x^{i}}{1-x}\)。那么回到这道题,根据上一题的结论,考虑 \(u,v\) 两个点什么时候 \(v\)\(u\) 的祖先,那么就是 \(v\)\([\min(u,v),\max(u,v)]\) 这个区间中最小的数。

\(u<v\) 的时候,按照 \(u,u+1,\dots,v,u-1,\dots,2,1,v+1,v+2,\dots,n\) 的顺序填数,否则我们按照 \(u,u-1,\dots,v,u+1,u+2,\dots,n-1,n,v-1,v-2,\dots,2,1\) 的顺序填数,容易发现这样的效果和之前是一样的,唯一不同的是 \(v\) 这个位置的逆序对数是确定的,不能算进贡献。\(u<v\) 时多贡献的逆序对数是 \(v-u\),否则是 \(0\),然后 \(|u-v|\) 这个 OGF 也不用贡献进答案。

那么就有了一个做法,枚举所有 \(|u-v|\),用多项式除法(回退背包),把这一项的贡献消除,然后枚举所有 \(u\),找到这一项 \(v\) 的贡献。

暴力实现多项式乘法+除法,总的复杂度是 \(O(n^3)\)code

例 6 HDU6854 Kcats

前缀 \(i\) 的单调栈大小,即 \(i\) 号节点在全局的笛卡尔树上对应的位置的所有在左边的祖先个数,考虑dp,设 \(f[l][r][d]\) 代表区间 \([l,r]\) 的笛卡尔树的根的左边祖先有 \(d\) 个的方案数。

转移即枚举最小值的位置 \(p\),然后从 \(f[l][p-1][d]\times f[p+1][r][d]\times \binom{r-l}{p-l}\) 转移。

复杂度 \(O(n^4)\),比较卡常,建议参考代码的卡常技巧。code

\(u\) 为根的笛卡尔树,代表一段区间,区间最小值是 \(u\) 上的值。区间 \([a,b]\) 的最小值是 \(lca(a,b)\) 上的值。所以当遇到区间 rmq 作为要求/条件/所求的时候不妨想一想笛卡尔树。

例 7 Periodni

https://www.luogu.com.cn/problem/SP3734

给定一个网格图,第 \(i\) 高度为 \(a_i\)。往网格里填 \(k\) 个数,同一列不能填两个数,同一行不能填两个数。如果中间有断开则不算同一行,问方案数。

要求即为对于同一行的数,放在高度 \(h\) 的位置,那么 \(\min_{i}^{j}a_i<h\)。看到这个区间最小值想到小根堆笛卡尔树,建出笛卡尔树后就是一个树形背包问题,然后转换为在 \(n\times m\) 的矩阵中选 \(k\) 个数的方案数,即为 \(k!\times \binom{n}{k}\binom{m}{k}\)。于是就可以直接dp了,复杂度 \(O(nk^2)\)

例 8 CF1580D Subsequence

https://codeforces.com/contest/1580/problem/D

将式子化以下,\((m-1)\sum a_{b_i}-2\sum_{i=1}^{m}\sum_{j=i+1}^{m}\min_{b_i\le k\le b_j}a_k\)
后面那个东西可以用笛卡尔树转换为 \(a_{lca(b_i,b_j)}\),然后我们定义边权为 \(a_i-a_{fa_i}\)
那么即可转换为选 \(m\) 个点使得其距离和最大,直接树形背包即可。

例 9 ZJOI2012 小蓝的好友

https://www.luogu.com.cn/problem/P2611

有一个 \(R\times C\) 的图,图上有 \(n\) 个随机的点,询问有多少矩形包含至少一个点。\(1\le R,C\le 4\times 10^4,1\le N\le 10^5\)

转换为对不包含任意一个点的矩形计数,考虑枚举矩形的底,求出每一列距离这一行最近的点的高度,记为 \(h_i\),然后转换为计数 \(\sum_{l\ge r}\min_{l\le k\le r}h_k\)。这个可以用笛卡尔树来维护,即维护 \(h_i\times (sz_{ls_i}+1)\times (sz_{rs_i}+1)\) 的和。还要可以单点修改,用 treap 维护,由于数据随机所以复杂度正确。

例 10 JOISC2020 星座 3

https://www.luogu.com.cn/problem/P7219

本题有一个很妙的贪心做法,但是和本文无关,所以就不再多做介绍。

两个星星是否可以组成一个星座,显然和他们之间的最高的小船有关,那看到这个自然想到笛卡尔树。考虑 dp,转换为求最大保留多少,如何消除后效性。容易发现最大值上方的部分只能保留一个,所以设 \(f[u][h]\) 代表 \(u\) 子树内最大星星高度是 \(h\)。暴力转移很显然,考虑如何优化。发现我们需要的时候区间加,对应位置合并求 \(\max\),以及单点修改,于是可以线段树合并维护,树上线段树合并时空复杂度均为 \(O(n\log n)\)

笛卡尔树本质是最值分治的结构

其实就是笛卡尔树的结构,找到最值,然后分成两边递归。

例 11 P4755 Beautiful Pair

https://www.luogu.com.cn/problem/P4755

有个数列 \(a\),当一个数对 \((i,j)\) 满足 \(a_i\)\(a_j\) 的积不大于 \(\max_{k=i}^{j}a_k\),这个数对是美丽的。请你求出美丽的数对的数量。

建出大根笛卡尔树,然后预处理出子树的区间,启发式分治,每次只遍历小的那一边,然后处理成区间询问。离线扫描线,然后离线扫描线即可。复杂度可以做到 \(O(n\frac{\log^2n}{\log\log n})\)code

例 12 IOI2018 meetings 会议

https://www.luogu.com.cn/problem/P5044

\(f[l][r]\) 代表区间 \([l,r]\) 的答案。设 \(x\in [l,r]\)\([l,r]\) 中最大的元素的位置。那么可以如此转移 \(f[l,r] = \min(f[l,x=1]+(r-x+1)\times h_x,f[x+1,r]+(x-l+1)\times h_x)\)

考虑建出笛卡尔树,那么对于 \(x\) 的子树,可以来维护对于区间内的 dp 值。考虑维护 \(f[l,x-1]\)\(f[x+1,r]\),如果这些值被维护出来后直接枚举询问就好了。假设 \(y\) 的父亲是 \(x\),不妨设 \(x\le y\),那么我们就是要维护 \(f[l,y-1],l\in sub(x)\)

那么根据转移方程 \(f[l,y-1]=\min(f[l,x-1]+h_x\times (y-x),f[x+1,y-1]+h_x\times (x-l+1))\),考虑用线段树来优化。首先先给第一部分区间加。而这个 \(f\) 显然是单调的,后者是一条直线,找到交点之后就可以区间赋值了,注意线段树pushdown的顺序,应该先赋值再加。对于右半边的部分直接继承就好啦。

其实也就是这个dp是一个分治信息,可以快速维护。最后的复杂度为 \(O((n+q)\log n)\)

笛卡尔树合并

可以参考之前2022.12.30的闲话。

posted @ 2023-01-13 23:30  Semsue  阅读(55)  评论(0编辑  收藏  举报
Title