『联合省选2025集训』『平衡树』Day2 略解
前言
对未来的真正慷慨,是把一切献给现在。
还是继续写总结。
A
日常被数据结构硬控刚好 \(\texttt{24h}\),除去睡觉时间不多不少刚刚好。
嗯,我看见 \(\texttt{XZJ}\) 也被控了差不多一天我就释然了。
然后 \(\texttt{OJ}\) 上过了,洛谷上面又卡了半年,才 \(\texttt{982MS}\) 极限卡过。
首先有一个比较好想的思路是,你考虑将一个僵尸分裂成两个,一个表示这个僵尸被右上方向撞上去,反弹后变成右下方向,一个表示这个僵尸被右下方向撞下来,反弹后变成右上方向。
然后考虑建边,找到每个僵尸对应方向上的第一个会撞到的下一个僵尸,连一条有向边。
(其实建边的过程还是不是很好写的,可以考虑用旋转公式转在一条线上,或者是你发现由于有反弹,本质上只有 \(2\times n-2\) 条不同的斜线,然后算出来每个点向右上或者右下对应的是哪根斜线。)
可以发现,在这样每个僵尸裂成两个点之后,图会形成若干条链,且互不相交,并且每个僵尸裂成的两个点会分别处于两条链上。
第一次操作显然就是找到每根轨道 \(x\) 最小的僵尸(然后注意要对准平地飞过去之后反弹的方向对应是裂成的哪个点。),看他在这条链上到链底的经过的点就是从他开始撞能撞死多少个僵尸。这个可以考虑最开始维护一个 \(\text{siz}_i\)
考虑中途僵尸死掉之后怎么把他从链上删掉。假设这个僵尸对应的点是 \(x,y\) 两个,考虑分别找到 \(x,y\) 在链上的上一个节点 \(X,Y\),在链上的下一个节点 \(X',Y'\),本质上就是从 \(X,Y\) 过来的时候,遇到这个僵尸不在反弹,所以删掉之后有 \(X\to Y',Y\to X'\)。然后改变这两条边之后,很多点的 \(\text{siz}\) 也是需要改变的,比如 \(X,Y\) 分别到其链顶上所有的点都要改变,可以使用平衡树维护,但是不知道为什么我直接暴力跳链顶没有超时。
这样我们就可以每次操作完之后,动态维护我们需要的 \(\text{siz}\),然后每次找到每根轨道上最前面的僵尸对应的 \(\text{siz}\) 的最大值即可,可以使用 \(\text{set}\) 维护。
特别注意两个细节,第 \(1\) 行不能裂成向上走的点,第 \(n\) 行不能裂成向下走的点,不然会自己连向自己。而且遇到重复的点,记录一下重复次数来维护,不能放任不管。
细节真的巨多,硬控我一天,所以我要立刻去 \(\texttt{PVZ}\) 里面暴打僵尸!!!
因为疑似暴力跳复杂度不太对,所以跑的巨慢,还卡了半天常。
B
先写今天的新课,有时间再来补。
C
简单题,以前还做过。
显然有一个策略,就你考虑枚举领导忍者的点,然后在他的子树中选择尽可能多的忍者使得薪水不超过 \(m\)。其实就是把子树内的忍者按照薪水从小到大排序然后找到一个临界点使得前面的忍者可以选。
可以使用线段树合并,或者可并堆,只要当前堆内的薪水总和大于 \(m\) 就把当前薪水最大的弹掉即可。
D
先写今天的新课,有时间再来补。