2022.8.22 闲话 — union
闲话储备也太不给力了,还让我现写 .
其实本来储备的是那个 Python 异常,不过想到 cnblogs 受众发现可以投首页候选就没选进闲话 .
猫树好难,不会啊 TAT
ECHO
THE CLOCK STOPPED TICKING FOREVER AGO
在很久之前时钟就已停止转动HOW LONG HAVE I BEEN UP? I DON'T KNOW 😦
我究竟醒来了多久 我不知道I CAN'T GET A GRIP, BUT I CAN'T LET GO
我无法将其守住但亦无法放手THERE WASN'T ANYTHING TO HOLD ON TO, THO
没有任何东西值得我去坚持WHY CAN'T I SEE??? WHY CAN'T I SEE???
为何我目及不到???为何我目及不到???ALL THE COLORS THAT YOU SEE??
你所目及到的全部色彩PLEASE CAN I BE PLEASE CAN I BE
请问我能否变得 请问我能否变得COLORFUL AND...free?
色彩斑斓的而且自由的吗WHAT THE HELL'S GOING ON?! CAN SOMEONE TELL ME PLEASE--
这究竟是怎么回事 谁来告诉我WHY I'M SWITCHING FASTER THAN THE CHANNELS ON TV
为何我切换得 比电视频道都要快I'M black THEN I'M white NO!!! SOMETHING ISN'T RIGHT!!
我是黑色 尔后变成白色 不 有什么不对劲MY ENEMY'S INVISIBLE, I DON'T KNOW HOW TO FIGHT
我的敌人是无形的 我不知道如何去战斗THE TREMBLING FEAR IS MORE THAN I CAN TAKE
颤栗着的恐惧 已超出我的承受能力WHEN I'M UP AGAINST THE ECHO IN THE MIRROR
当我与镜子中的 回声对峙ECHO
ECHOit's time to let go
是时候放手了bury it down to the ground
把它烧到地上and to break all the silence
打破所有沉默see what i become now
看看我现在是怎么来的when i cut the tall from the past
从信息的尾巴look round the world and that's what I've got
环游世界 这就是我得到的broken screen flashing around
破碎的屏幕周围在闪烁It's not the end of the game
这不是游戏的结尾it's not
这不是but now I got caught in a riddle
但我现在遇到一个迷once you looking inside never know how to look back
一旦你在里面看就永远不知道如何回头then I heard the echo laugh
然后我听到回声笑so i burn it all down to the ground
所以我燃烧的一切都倒在地上make it all dead before I hear a sound
让这一切死之前我听到一个声音everything is quite i look into the mirror.
这一切都是安静的我照着镜子and see the beast that’s what i've become
看到野兽 这是我所成为的it's not the way i've wanted
这不是我想要的方式but i standing in a mess that I made
但我在一个烂摊子 我做了then i cried
然后我哭了the echo in the mirror still laughing at me
我恸哭中 镜子中的回声依旧嘲笑着我i could never get peace of my mind in my life
我甚至不能在我的生命中得到一丝安宁i'm gonna burn my house down into an ugly black
我必须把我的房子烧毁成狰狞的黑色i'm gonna run away now and never look back
我此刻就要逃离永远不再回头i'm gonna burn my house down into an ugly black
我必须把我的房子烧毁成狰狞的黑色i'm gonna run away now and never look back
我此刻就要逃离永远不再回头i'm gonna burn my house down into an ugly black
我必须把我的房子烧毁成狰狞的黑色i'm gonna run away now and never look back
我此刻就要逃离永远不再回头i'm gonna burn my house down into an ugly black
我必须把我的房子烧毁成狰狞的黑色i'm gonna run away now and never look back
我此刻就要逃离永远不再回头i'm gonna burn my house down and never look back
我必须把我的房子烧毁成狰狞的黑色and never look back
再也不回头 永不回头AND NEVER LOOK BACK
再也不回头 永不回头WHAT THE HELL'S GOING ON?! CAN SOMEONE TELL ME PLEASE--
这究竟是怎么回事 谁来告诉我WHY I'M SWITCHING FASTER THAN THE CHANNELS ON TV
为何我切换得 比电视频道都要快I'M black THEN I'M white NO!!! SOMETHING ISN'T RIGHT!!
我是黑色 尔后变成白色 不 有什么不对劲MY ENEMY'S INVISIBLE, I DON'T KNOW HOW TO FIGHT
我的敌人是无形的 我不知道如何去战斗WHAT THE HELL'S GOING ON?! CAN SOMEONE TELL ME PLEASE--
这究竟是怎么回事 谁来告诉我WHY I'M SWITCHING FASTER THAN THE CHANNELS ON TV
为何我切换得 比电视频道都要快I'M black THEN I'M white NO!!! SOMETHING ISN'T RIGHT!!
我是黑色 尔后变成白色 不 有什么不对劲MY ENEMY'S INVISIBLE, I DON'T KNOW HOW TO FIGHT
我的敌人是无形的 我不知道如何去战斗THE TREMBLING FEAR IS MORE THAN I CAN TAKE
颤栗着的恐惧 已超出我的承受能力WHEN I'M UP AGAINST THE ECHO IN THE MIRROR
当我与镜子中的 回声对峙THE TREMBLING FEAR IS MORE THAN I CAN TAKE
颤栗着的恐惧 已超出我的承受能力WHEN I'M UP AGAINST THE ECHO IN THE MIRROR
当我与镜子中的 回声对峙
SoyTony 忒的歌:
浪子回头
《浪子回头》
烟一支一支一支的点
酒一杯一杯一杯的干
请你要体谅我
我酒量不好卖给我冲康
时间一天一天一天的走
汗一滴一滴一滴的流
有一天 咱都老 带某子逗阵
浪子回头
亲爱的 可爱的 英俊的 朋友
垃圾的 没品的 没路用的 朋友
伫坎坷的路骑我两光摩托车
横竖我的人生甘哪狗屎
我没钱没某没子甘哪一条命
朋友啊 逗阵来搏
烟一支一支一支的点
酒一杯一杯一杯的干
请你要体谅我
我酒量不好卖给我冲康
时间一天一天一天的走
汗一滴一滴一滴的流
有一天 咱都老 带某子逗阵
浪子回头
伫坎坷的路骑我两光摩托车
横竖我的人生甘哪狗屎
我没钱没某没子甘哪一条命
朋友啊 逗阵来搏
烟一支一支一支的点
酒一杯一杯一杯的干
请你要体谅我
我酒量不好卖给我冲康
时间一天一天一天的走
汗一滴一滴一滴的流
有一天 咱都老 带某子逗阵
带某子逗阵
带某子逗阵
以下所有问题若无特殊说明均为强制在线 .
一般信息合并问题:
General Merger
给一个序列 \(\{a_n\}\) 和一个的二元运算 \(\circ\),每次给一个区间 \([l,r]\),计算 \(a_l\circ a_{l+1}\circ\cdots\circ a_r\) .
做法:
- 可减(\(\circ\) 存在逆运算):前缀和 .
- 可重复贡献(\(a\circ a = a\)):线段树 / ST 表 / The Method of Four Russians .
- 结合律(\((a\circ b)\circ c=a\circ(b\circ c)\))且可快速合并:\(k\) 区间合并 .
几个例子:
- 可减:和,异或和
- 可重复贡献:max,gcd .
- 结合律且可快速合并区间:最大子段和,奥秘 Hash 值 .
ST 表
区间最值问题
静态 RMQ
给一个序列 \(\{a_n\}\),\(q\) 次询问,每次给一组 \([l,r]\),求 \(\displaystyle\min_{i\in[l,r]}a_i\) .
\(n,q\le 3\times 10^6\) .
考虑倍增,令 \(f_{i,j}\) 表示 \(\displaystyle\min_{k\in[i,i+2^j-1]}a_k\),则我们可以轻易递推出所有点值
注意到 \(\min\{a,a\} = a\),所以询问的时候我们把一个整区间拆成前后两段长度为二的次幂的区间然后取 max 即可,长度为二的次幂的区间 max 就是 \(f\) .
\(f\) 的第二维 \(j\) 只有 \(\Theta(\log n)\) 个有用取值,于是预处理时间复杂度 \(\Theta(n\log n)\),询问时间复杂度 \(\Theta(1)\) 的静态 RMQ 就出现了 .
这个一般叫做 ST 表 .
Pushback RMQ
给一个序列 \(\{a\}\),\(q\) 次操作:
1 x
,在 \(\{a\}\) 的末尾追加数 \(x\) .2 l r
,求 \(\displaystyle\min_{i\in[l,r]}a_i\) .令 \(n\) 为所有操作执行完之后 \(\{a\}\) 的长度,则 \(n,q\le 3\times 10^6\) .
注意到每次只在末尾添加,考虑 ST 表维护 \(f\) 的过程,显然在末尾加一个数只会影响到 \(\Theta(\log n)\) 处 \(f\) 的点值,于是我们大力把这些点更新一下即可 .
这样的时间复杂度就是:
- 预处理:\(\Theta(n\log n)\) .
- 操作 1:\(\Theta(\log n)\) .
- 操作 2:\(\Theta(1)\) .
Stack RMQ
给一个序列 \(\{a\}\),\(q\) 次操作:
1 x
,在 \(\{a\}\) 的末尾追加数 \(x\) .2
,删掉 \(\{a\}\) 末尾的数,保证操作时序列长度大于 \(1\) .3 l r
,求 \(\displaystyle\min_{i\in[l,r]}a_i\) .令 \(n\) 为每个时刻中 \(\{a\}\) 的最长长度,则 \(n,q\le 3\times 10^6\) .
发现如果我们还用 Pushback RMQ 的方法那么 2
比较难处理,因为 chkmin 这个操作是不可逆的 .
我们对每个 \(f\) 值开两个栈,这样会有 \(\Theta(n\log n)\) 个栈 .
两个栈暂且叫做栈 A,栈 B,那么对于每个 \(f\),如果新来一个 \(x\) 要 chkmin 就给它扔到栈 A 里,如果最小值变动就把它也扔到栈 B 里 .
弹的时候先看一下栈 A 的栈顶和栈 B 的栈顶是否相同,如果相同就同时弹,否则只弹栈 A,显而易见这样操作栈 B 的栈顶永远都是栈 A 中所有元素的最小值,也就是我们要维护的东西 .
这样对于每次弹和加只需要 \(\Theta(1)\) 次操作栈,栈内元素个数是 \(\Theta(q\log n)\) 级别的,于是时间复杂度就是:
- 预处理:\(\Theta(n\log n)\) .
- 操作 1:\(\Theta(\log n)\) .
- 操作 2:\(\Theta(\log n)\) .
- 操作 3:\(\Theta(1)\) .
空间复杂度 \(\Theta(q\log n)\),也不是那么不优秀 .
信息合并
仔细分析一下,ST 表要维护的二元运算需要有什么性质呢?
不难发现,二元运算 \(\circ\) 如果满足如下性质,那么就可以用 ST 表来维护区间 \(\circ\):
- 交换律:\(a\circ b=b\circ a\) .
- 结合律:\((a\circ b)\circ c=a\circ(b\circ c)\) .
- 可重复贡献:\(a\circ a = a\) .
可重复贡献是非常关键的,如果不可重复贡献实际上要 ST 表硬维护就变成等价于线段树的结构了(当然时间复杂度也和线段树一样) .
以上三个性质的交我们就称作 ST 表性质 .
区间 GCD
给一个序列 \(\{a_n\}\),\(q\) 次询问,每次给一组 \([l,r]\),求 \(\displaystyle\gcd_{i\in[l,r]}a_i\) .
\(n,q\le 3\times 10^6\) .
\(\gcd\) 是满足 ST 表性质的二元运算的一个经典实例 .
类似的,以下运算具有 ST 表性质:
- min,max
- 按位与,按位或(相当于按位 min/max)
- gcd, lcm(相当于在素因子维度上 min/max)
幸运数字 下树
给一个序列 \(\{a_n\}\),多组询问,每次给一个区间 \([l,r]\),要求选一个集合 \(S\subseteq[l,r]\cap\mathbb Z\),并使得
\[V_a(S)=\bigoplus_{k\in S}a_k \]最大,只需输出最大的 \(V_a(S)\) .
\(n,q\le\times 10^5\),\(\forall i, a_i\le 2^{60}\) .
这个区间询问的是经典线性基问题,令 \(\displaystyle B=\max_i\{\log_2a_i\}=60\) 则线性基合并可以在 \(\Theta(B)\) 时间内解决 .
于是我们用 ST 表方法处理一下即可得到区间的线性基,然后贪一下即可得到最大异或和,预处理 \(\Theta(nB\log n)\),询问 \(\Theta(B)\) .
最近公共祖先
Naive LCA
给一棵 \(n\) 个点的有根树 \(\mathcal T\),多组询问,给定两个点 \(u,v\),找一个点 \(x\),使得:
- \(x\) 是 \(u\) 的祖先 .
- \(x\) 是 \(v\) 的祖先 .
- \(x\) 的深度最大(深度定义为点到根节点的距离).
\(n,q\le 10^6\) .
暴力思路:找到 \(u,v\) 中深度较大的,然后先暴力跳到和小的那个深度一样,然后一起往上跳,如果重合了那么就找到 \(x\) 了 .
定义 \(f_{u,k}\) 表示 \(u\) 的 \(2^k\) 级祖先,也可以 \(\Theta(n\log n)\) 预处理,和 ST 表差不多 .
然后跳的时候把隐式地把需要的步数二进制分解即可单次 \(\Theta(\log n)\)(即倍增流程).
相当于把一条直链分解成 \(\Theta(\log n)\) 条长度为二的次幂的直链,这些直链两两不交 .
这个 \(x\) 也就是 \(u,v\) 的 LCA,后记作 \(x=\operatorname{LCA}(u,v)\) .
Distance
给一棵 \(n\) 个点的有根树 \(\mathcal T\),多组询问,每次给定两个点 \(u,v\),求 \(u,v\) 间唯一简单路径的长度 \(\operatorname{dist}(u,v)\) .
\(n,q\le 10^6\) .
Algorithm 1:\(\operatorname{dist}(u,v)=\operatorname{dep}(u)+\operatorname{dep}(v)-\operatorname{dep}(\operatorname{LCA}(u,v))\),其中 \(\operatorname{dep}\) 是深度,直接算 LCA 即可 .
Algorithm 2:记 \(s_{u,k}\) 表示 \(u\) 到其 \(2^k\) 级祖先的距离,那么类似倍增 LCA 的思路求即可 .
时间复杂度均为 \(\Theta((n+q)\log n)\) .
Bonus:带权 .
其实也不算 Bonus,因为和原题一模一样嘛 .
Max
给一棵 \(n\) 个点的带权有根树 \(\mathcal T\),多组询问,每次给定两个点 \(u,v\),求 \(u,v\) 间唯一简单路径的边权 max .
\(n,q\le 10^6\) .
类似 Distance 的 Algorithm 2,记 \(s_{u,k}\) 表示 \(u\) 到其 \(2^k\) 级祖先的链 max,那么类似倍增 LCA 的思路求即可 .
时间复杂度 \(\Theta((n+q)\log n)\) .
MST
给一棵 \(n\) 个点的带权树,对于每条边,求出必须包含这条边的 MST 边权和 .
\(n\le 10^6\) .
类似,首先建出全局 MST,然后一条边的两个端点肯定都在树上,于是钦定一条边必须选就在两端点对应树的唯一简单路径间找到边权最大的删了即可,正确性显然(MST 是一棵树并且边权最小).
时间复杂度 \(\Theta(n\log n)\) .
幸运数字
给一棵 \(n\) 个点的有根树 \(\mathcal T\),每个点 \(u\) 有点权 \(a_u\),多组询问,每次给定两个点 \(u,v\),令 \(u,v\) 间的唯一简单路径的点集为 \(\operatorname{path}(u,v)\),则要求选一个集合 \(S\subseteq\operatorname{path}(u,v)\),并使得
\[V_a(S)=\bigoplus_{k\in S}a_k \]最大,只需输出最大的 \(V_a(S)\) .
\(n,q\le\times 10^5\),\(\forall i, a_i\le 2^{60}\) .
在 幸运数字 下树 上套一个倍增 LCA 即可,\(\log\) 的数量取决于实现的狂暴精细程度 .
The Method of Four Russians
先 \(O(n)\) 建序列的笛卡尔树,不难发现两个点之间的最小值就是它们的 LCA 的权值 .
使用基于 RMQ 的树上 LCA 算法,发现笛卡尔树的欧拉序相邻两个节点深度差必然为 \(\pm 1\) .
我们假设我们在 word-RAM model 中 .
由于相邻两个元素之差为 \(1\),那么长度为 \(n\) 的本质不同的序列只有 \(2^n\) 个 .
考虑将序列按照 \(\dfrac12\log n\) 分段,在 word-RAM model 中,一个常见的假设是字长 \(w\ge \log n\),注意到长度为 \(\dfrac 12\log_2 n\) 的本质不同的数列只有 \(O(\sqrt n)\) 个,我们可以枚举所有可能的情况,并枚举左右端点,这可以在 \(O(\sqrt n\log^2 n)\) 的时间复杂度内完成 .
因为一个数列长度为 \(n\) 的数列可以用二进制串编码(对于一个序列 \(a\),其二进制串编码的第 \(j\) 位为 \([a_j<a_j+1]\)).
对于分成的 \(O\left(\dfrac{n}{\log n}\right)\) 段,使用 ST 表维护 .
从而对于零散块来说,查表即可得出答案,我们也就得到了 \(O(n)-O(1)\) 的算法 .
优化:对于每个块维护一个单调队列,再把单调队列状压 .
k 区间合并
\(k\) 区间合并解决的问题为维护有结合律的静态区间运算 .
即
Dynamix
给一个序列 \(\{a_n\}\) 和一个满足结合律的二元运算 \(\circ\),每次给一个区间 \([l,r]\),计算 \(a_l\circ a_{l+1}\circ\cdots\circ a_r\) .
以下 \(O(f(n))\) 预处理 \(O(g(n))\) 查询记作复杂度 \(O(f(n))-O(g(n))\) .
听说存在 \(O(n\alpha(n))-O(1)\) 做法,大概不是 \(k\) 区间合并 .
二区间合并 / 猫树
不会 .
三区间合并 / Sqrt Tree
三区间合并复杂度是 \(O(n\log\log n)-O(1)\) 的 .
以下三区间合并都叫做 Sqrt Tree .
假设我们要维护的二元运算是 \(\circ\),则首先对序列分块,块长是根号,对于每个块维护前缀后缀 \(\circ\),块间维护一个数组 \(B_{i,j}\) 表示第 \(i\) 个块到第 \(j\) 个块的 \(\circ\) 和 .
这个可以 \(O(n)\) 预处理,于是跨块的询问就可以 \(O(1)\) 处理了,整块内用同样的结构分治,可以用一棵树的形式维护,显而易见树高是 \(O(\log\log n)\) 的,于是现在的复杂度就是 \(O(n\log\log n)\) 预处理 / 建树,\(O(\log\log n)\) 查询 .
询问详细来说就是先快速找到一个区间长度最小的结点 \(u\) 使得 \(u\) 能包含 \([l,r]\),这样 \([l,r]\) 在目前层必然跨块,于是就可以 \(O(1)\) 回答 .
不难想到二分高度,显然可以 \(O(1)\) check,于是询问复杂度变成了 \(O(\log\log\log n)\) .
我们考虑一个理想情况,\(n\) 是二的次幂,这样每块大小都是二的幂,并且同层块大小相等 .
观察发现在对于第 \(k\) 层同一个块内的元素的位置在二进制上只有后 \(k\) 位不同,于是每个区间 \([l,r]\) 算一下 \(\operatorname{highbit}(l\oplus r)\) 就可以确定层了,这样就 \(O(1)\) 询问了 .
不是二的次幂的需要补成二的次幂,复杂度不变 .
静态的三区间合并还是比较平凡的,带区间赋值的高端 Sqrt Tree 可以见 OI Wiki .
四区间合并
四区间合并:首先序列分块预处理块内前缀和,块间用二区间合并,然后小块内部的查询继续分块,\(O(n\log^* n)-O(1)\) .
有人不知道 \(\log^*\) 吗?\(\log^*(n)=\begin{cases}1&n<1\\\log^*(\log(n)) + 1 & \text{otherwise.}\end{cases}\) .
「为什么哭呢?」
“因为自己的期许和现实相去甚远。”
「哭能改变什么呢?」
“什么都不能。正如同既成事实的过去一样。”
「那么为何不抹去泪水向前迈进呢?」
“… 我在等我的灵魂追上时间。”
以下是博客签名,正文无关
本文来自博客园,作者:Jijidawang,转载请注明原文链接:https://www.cnblogs.com/CDOI-24374/p/16613609.html
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0)进行许可。看完如果觉得有用请点个赞吧 QwQ