「2022-8-15 做题笔记」差分 & 并查集 & 树剖
Minimum Cut
还是很妙的。
考虑一种做法是主席树:对于非树边 \((x,y)\),\(x\in [dfn_i,dfn_i+siz_i-1]\),\(y\notin [dfn_i,dfn_i+siz_i-1]\)。主席树维护即可。
当然,这种问题我们一般看 \(x\) 到 \(y\) 的路径上有没有什么限制,发现一条非树边仅能给 \(x\) 到 \(y\) 的路径上的边提供贡献。
所以树上差分即可。
差分。广义差分。
Juju and Binary String
个数最少 -> 有可能只是 \(1\) 或 \(2\)。
为什么题目一定要求与原串的可爱度相等。鸽巢原理?
然而,转化一下,令 \(A\) 为原串 \(1\) 的个数,\(B\) 为原串 \(2\) 的个数。如果是 \(1\),就加 \(B\),是 \(2\) 就减 \(A\)。即求总和为 \(0\) 的子串。
发现,因为原串总和为 \(0\)。所以子串一定会由正 -> 负,或 负 -> 正。由于每次修改 \(1\) 的个数只会增加 \(1\) 个,所以是连续的,所以一定有一个子串和为 \(0\)。做完了。
「JOISC 2014 Day3」电压
出题人的思路很精妙。
删掉这条边后没有奇环。
分类讨论。若没有奇环,每一条边都可以。
如果它不是树边。那么它一定在唯一的奇环上(与剩下的树边组成)(与其他非树边组合不会产生影响,可以推一推)
如果它是树边。那么它一定在所有的奇环中,且不在偶环中。
树上差分即可。注意多个连通块拼起来是有细节的。
「JOISC 2019 Day2」两道料理
。。。dp 的状态就是 \(n^2\) 的啊。。。
能不能基于线段树操作?
转化成笛卡尔坐标系,注意到这里只有两个选法,对应坐标系中的横纵坐标。
每个贡献都可以转化为一个坐标。对于盖饭 \(i\) 的贡献,有个坐标 \((i,p_i)\)。如果我们的路径在它下面(或包含它),那么这个贡献可取。
对于咖喱 \(i\) 的贡献,有个坐标 \((q_i,i)\)。如果我们的路径在它上面(或包含它),那么这个贡献可取。
一个上面一个下面。不好统一。那就简单容斥一下。强制都选咖喱,咖喱的贡献就与盖饭统一了。
令 \(dp_{i,j}\) 为走到 \((i,j)\) 的最大贡献。\(dp_{i,j}=\max \{dp_{i-1,j}+val_{i-1,j},dp_{i,j-1}\}\)。就是,我们钦定在一个竖条的最高的位置统计答案。
发现对于同一个 \(i\),\(dp_{i,j}\) 是单调递增的,而且 \(val_{i-1,j}\) 发生改变的位置只有 \(2n\) 个,因此想到差分。
如果加的是个正数,差分数组直接加即可。
如果加的是个负数,考虑差分数组中不会出现负数,所以往后一直推,使 \(d_i=d_{i}+d_{i-1}\)。\(d_i\) 为非负数时停止。由于每推一下会使差分数组中多出现一个 \(0\),只要我们往后只推有值的地方,均摊次数是 \(2n\)。当然加上最后那个有值的点就是 \(4n\) 啦。
这个东西可以用 \(\mathrm {set}\) 维护,时间复杂度 \(\mathcal {O}(n\log_2n)\)。
当然也可以用线段树上二分维护,就不用考虑均摊了。
CF1446D1 Frequency Problem (Easy Version)
CF1446D2 Frequency Problem (Hard Version)
😓
不会。。。考虑答案区间众数与全局众数的关系。
发现:区间众数一定包含着全局众数。(这个可以手玩找规律)
因为假设我们已经得到了一个答案区间。我们可以一直扩展区间,使得区间众数数量等于全局众数数量。
那么,如果区间众数有很多个,答案就是 \(n\)。
\(\mathcal {Easy\ Version}\):\(a\leqslant 100\)。考虑固定左端点,右端点肯定选能选到的最远位置,满足众数的个数不超过 \([l,n]\) 全局众数的最大出现次数。等等,主席树上二分可以做到 \(\mathcal {O}(n\log_2n)\)。吊打标程了。(?)(有时间再来检验)
但,枚举每一个数。做一遍前缀和,如果是全局众数就减 \(1\),是这个数就加 \(1\)。答案转化为相距最大的 \(pre\) 相等的位置。桶记录一下即可。
\(\mathcal {Hard\ Version}\):
-
上面做法最远似乎扩展到值域为 \(\sqrt n\) 的情况。
-
考虑关注区间众数出现次数。
如果 \(>\sqrt n\),这样的数只有 \(\sqrt n\) 个。可以使用刚才的算法。
如果小于 \(\sqrt n\)。出现次数 \(< \sqrt n\),枚举出现次数 \(i\)。固定右端点,发现左端点就是最远的使区间里的数出现次数都 \(\leqslant i\) 的。\(\mathrm {two\ pointers}\) 即可,但要判断是否合法,即出现次数最多的数是否有两个及以上。
时间复杂度 \(\mathcal {O}(n\sqrt n)\)。
现在看来做法真的很自然。
一开始想到的启发式合并。
设 \((x,y)\) 的并查集根节点为 \(u\)、\(v\),对于边 \((s,t)\),如果 \(fa_s=u,fa_t=v\),那么就确定值为 \((x,y)\) 的值。用 vector 维护。但是这个复杂度会伪。。。(不过出题人应该不会刻意卡这个(?))
先对值确定的边跑一遍 mst?
好吧,先固定这些边,剩下的加进来跑 mst。然后没加进来的在树上做个最大值覆盖就可以了。