笛卡尔树

附近都是喜欢花自己时间耗别人时间和心态,不想宽容别人占用自己时间的人。这些人全是傻逼,所以我开始写这个了。

这里先喷一下。

傻逼啊!我造题,我一句话没说,草泥马的一直叫,叫的还贼难听。日了狗了我真的听够了,就好像你他妈是我上司,我就是下属,就该造题。傻逼才会这么想吧!日马口气极为臭,请搞清楚是我们在无偿做事!至少我不怕说损坏了什么个人名誉甚至是集体名誉。这个集体几乎没帮过我什么,除了挂题,不过那都是小事,我维护 oj 的时间比这个多多了。你们天天都是有事有事,反而是我天天给别人讲题!最弱的给别人讲题,你想想!!!搞明白一点吧!!!

我不管了,这个集训我已经几乎受够了。出 3 次外卖事故的是我,造题最后题没了的也是我,比大多数人做出来连考题少的人也是我!!!我自己揽的活我承认,但是你就别用这种傻逼口气叫,讲题也只讲个状态。就好像什么理都在你们那边。

反正我不想收场了,这个事情不值得我素质高。

好了该补这个知识点了。

笛卡尔树是一个结构描述二元组 \((a_i,b_i)\) 构成的序列。使得对于 \(a_i\),这棵树是用二叉搜索树来描述的;且对于 \(b_i\),这棵树是按照堆来描述的。

常用的就是对于一个排列去建出大根笛卡尔树或者小根笛卡尔树。此时二元组就是 \((i,a_i)\)

我们容易得出笛卡尔树的 \(O(n\log n)\) 建法,就是直接建一个 ST 表,然后递归处理。

但是实际上我们有简单的 \(O(n)\) 建法。以下是以建小根笛卡尔树为例。

考虑顺序建树,每次加入一个数 \(a_i\),记录 \(i-1\) 位置的数目前的位置。因为下一个数需要满足二叉搜索树的限制,所以我们找到到根链上第一个小于 \(a_i\) 的数,我们就一定把这个数放到它的右子树上。如果这个右子树已经存在,那就放到目前加入的点的左子树上。

显然发现这样加入那么记录的位置到根链就全部是右儿子。需要特判根都比目前的数大。

显然暴力跳是对的,因为相当于 DFS 了一遍整个树。代码是好写的。

代码
#include<bits/stdc++.h>
using namespace std;
const int M=1e7+5;
int n,a[M];
unsigned long long ans1,ans2;
int fa[M],L[M],R[M],rt,now;
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	now=1;
	for(int i=2;i<=n;i++){
		while(fa[now]&&a[i]<a[fa[now]])now=fa[now];
		if(a[now]<a[i]){
			fa[i]=now;R[now]=i;
		}else{
			fa[i]=fa[now],R[fa[now]]=i,fa[now]=i;
			L[i]=now;
		}
		now=i;
	}
	for(int i=1;i<=n;i++)ans1^=1ull*i*(L[i]+1),ans2^=1ull*i*(R[i]+1);
	cout<<ans1<<" "<<ans2<<"\n";
	return 0;
}

当然有些例题。

P1377 [TJOI2011] 树的序

众所周知,二叉查找树的形态和键值的插入顺序密切相关。准确的讲:

  1. 空树中加入一个键值 \(k\),则变为只有一个结点的二叉查找树,此结点的键值即为 \(k\)
  2. 在非空树中插入一个键值 \(k\),若 \(k\) 小于其根的键值,则在其左子树中插入 \(k\),否则在其右子树中插入 \(k\)

我们将一棵二叉查找树的键值插入序列称为树的生成序列,现给出一个生成序列,求与其生成同样二叉查找树的所有生成序列中字典序最小的那个,其中,字典序关系是指对两个长度同为 \(n\) 的生成序列,先比较第一个插入键值,再比较第二个,依此类推。

\(1\leq n\leq 10^5\)

观察它上面定义的二叉查找树,发现生成序列的置换的小根笛卡尔树即为它生成的树。

要求最小的生成序列,相当于我们贪心的去想每次第一个数最小。那么中左右遍历一遍二叉树输出下标即可。

P9607 [CERC2019] Be Geeks!

音乐乐队 Be Geeks! 的名字并非偶然,因为所有成员都是真正的数学怪才。除此之外,他们喜欢研究数列的各种性质。下面是他们感兴趣的一个例子:

  • \(A\) 是一个非空正整数序列,\(A=(a_1, a_2, \dots, a_N)\)
  • \(G(i, j)=\gcd (a_i, a_{i+1}, \dots, a_j)\),其中 \(1\le i\le j\le N\)
  • \(M(i, j)=\max (a_i, a_{i+1}, \dots, a_j)\),其中 \(1\le i\le j\le N\)
  • \(P(i, j)=G(i, j)\times M(i, j)\),其中 \(1\le i\le j\le N\)
  • \(F(A)=\sum P(i, j)[1\le i\le j\le N]\)

给出一个序列 \(A\),你需要求出 \(F(A)\bmod 1000000007\) 的值。

\(1\leq N\leq 2\times 10^5\)

笛卡尔树是可以把树论的一些东西套上去的。

笛卡尔树分治。每次考虑跨过 \(\max\) 值的区间。则 \(M(i,j)\) 的部分是固定的。现在只需要考虑这部分的 \(\gcd\) 之和。但是注意到 \(\gcd\) 只会变化 \(O(\log V)\) 次,所以可以先枚举小的那边,然后通过 \(O(\log V)\) 次二分得到大的那边的分割点。注意这样的话我们需要一个 ST 表求区间 \(\gcd\),这样是 3log 的。

根据经典结论,把二分换成倍增,复杂度就均摊掉 1 个 log。

枚举小的那段的复杂度对是因为这个相当于启发式合并。

P10919 运输规划

大家都喜欢。

\(n\) 个城市,对于任意 \(1 < i \leq n\) 满足第 \(i\) 个城市与第 \(i-1\) 个城市间有一条双向的道路,每个城市有一个对卡车高度的限制 \(h_i\),代表只有高度小于等于 \(h_i\) 的卡车可以从这个城市经过,现在有 \(m\) 个城市 \(S_{1},S_{2},...,S_{m}\) 各有恰好一个运输任务,任务要求编号为 \(i\) 且高度为 \(h_{S_{i}}\)卡车从城市 \(S_{i}\) 出发到达任意一个有机场的城市,而有 \(m\) 个城市有机场,分别为 \(T_{1},T_{2},...,T_{m}\),对于一个合法的运输方案而言,需要保证每个卡车都到达一个机场且每个机场恰好有一辆卡车抵达。一个机场可以同时被多辆卡车经过。请注意,如果你无法经过某个城市,那么你也无法抵达这个城市。

\(c_i\) 表示抵达位于城市 \(T_i\) 的机场的的卡车编号,令数组 \(F = \{c_1,c_2,...,c_m\}\),请你最小化 \(F\) 的字典序并输出 \(F\)

我们定义两个长度为 \(len\) 的数组 \(A,B\) 满足 \(A\) 的字典序小于 \(B\) 当且仅当存在 \(0 \leq i < len\) 满足对于任意 \(1 \leq j \leq i\) 满足 \(A_j = B_j\)\(A_{i+1} < B_{i+1}\)

数据保证有解,保证所有 \(h_i\) 互不相同,所有 \(T_i\) 互不相同,所有 \(S_i\) 互不相同。但是可能会存在 \(i,j\) 满足 \(S_i = T_j\)

\(1\leq n,m\leq 2\times 10^5\)

Hall 定理直接套上。注意读题,我们要求的是 \(T\) 匹配什么 \(S\) 的序列对应的字典序最小排列。考虑 Hall 定理的 \(|S|\leq N(S)\),所以我们可以非常容易想到维护对于 \(S\)\(N(S)-|S|\) 最小值。这个最小值一定等于 \(0\)。注意到 \(S\)\(|S|\) 和其对应的 \(N(S)\) 都可以在笛卡尔树上用一个子树描述,所以其实我们就是相当于维护每个子树的 \(N(S)-|S|\)。去掉一个 \(S\) 就是 \(|S|\) 减,去掉 \(T\) 就是 \(N(S)\) 减。

这个时候已经非常明了了,我们相当于对于一个 \(T\) 找到上面最近的 \(0\) 点,这个点以上的 \(S\) 一定不合法。在这个路径上找到一个最小的 \(S\) 即可。

可以用树剖 + 线段树 + set 维护。

有一个几乎一样的题。不过是 BOJ 的。那个题就是点连排列的一个区间,扫描线类似分析即可。不过这不在笛卡尔树范畴之内。

P9152 待黑白分明

要趁黎明还

没有到来之前

无数的命运线伏延

谁与谁的轨迹交叠

不用倾注太多语言

行动回应眼前一切

握住手中仅存岁月

尝试剥去内心假面

成为彼此生命中最独特最珍贵那页

待到黑白已然分明......

以上不是题面。

Shiro 所在的城市可以看成数轴上 \(n\) 个坐标连续的点,其中 \(i\) 号点的高度为 \(p_i\),保证 \(p\) 是一个 \(\{1,2,\ldots,n\}\) 的排列。

3202 年的科技非常发达,发展出了虫洞列车技术。共有 \(n\) 种列车,第 \(i\) 种列车会经过所有高度大于等于 \(i\) 的位置,每种列车线路都是双向的,也就是说可以乘列车从左到右,也可以从右到左。

Shiro 想在城市里转转,她定义一个位置集合 \(S\) 合法,当且仅当我们将 \(S\) 中的位置按照高度排序后,相邻的城市可以通过乘坐一种列车在中途不停靠的情况下直达。

她会给你 \(q\) 次询问,每次给定 \(l,r\),你需要告诉 Shiro 所有位置的高度均在 \([l,r]\) 内的合法集合 \(T\) 的数量对 \(998244353\) 取模的结果。

\(1\le n,q\le 2\times {10}^5\)

最后一题。

后面的 DS 部分就简单点讲。这题卡时间和空间,素质极差。

这个题面非常让人摸不着头脑。不过如果你读懂了的话,就可以开始分讨什么位置能到达这个位置。

如果这个题你想到了笛卡尔树,那你就很牛了。作者是知道这是笛卡尔树的情况下做的,不过遇到这种排列跟值全部小于大于某个值或者直接摆明是 \(\max\) 或者 \(\min\) 的就可以往这边想了。

限制很史对吧?化成我们知道的东西!那么一点到另外一点一定满足什么?假设是 \(p\to q\),其实容易写出:

\[\min(a_p,a_q)\geq i\\ \max_{j=p+1}^{q-1}(a_j)\leq i \]

因为只需要让一个 \(i\) 满足即可,所以相当于限制变为:

\[\min(a_p,a_q)>\max_{j=p+1}^{q-1}(a_j) \]

这个时候其实笛卡尔树已经比较明了了,但是还是很难看出来。建出大根笛卡尔树。一个点能被其左儿子的右儿子链和右儿子的左儿子链转移。如果是单组询问那就直接 DP 就做完了。

然后呢?值域 \(n\to 1\) 扫描线,每次加入一个点。因为大的不会影响小的的 DP 值,所以我们相当于求值 \(\leq r\) 的所有 DP 值和。

树上随机撒点分块,每次两种转移,暴力跳父亲转移到父亲上,然后逐块处理其根对其他所有点的贡献,在值域上做一个前缀和算出贡献系数即可。

需要一些卡常。

posted @ 2024-11-26 21:26  xingyu_xuan  阅读(13)  评论(0编辑  收藏  举报