[NOI 2020] 命运
一些闲话:完了完了好废啊,这题都没做过是不是药丸。根本没有想到子树 \(\tt dp\),没有注意到每条路径都是 "祖先 \(\to\) 子孙" 这个形式的提示欸……
记 \(dp(u,i)\) 为已经考虑子树 \(u\) 内边的赋值情况,目前 未满足 且下端点属于子树 \(u\),上端点深度最大值为 \(i\)(特别地,如果全满足则为零)的子树内边赋值方案数。对于父子关系 \(u\to v\) 有这样的转移
转移基于边 \((u,v)\) 的赋值情况分类讨论。第一个和式是赋值为 \(1\) 的情况,此时对于 \(j\leqslant d_u\) 的 \(dp(v,j)\) 一定都满足了之前未满足的限制,而且由于 \(i<d_u\)(否则不可能合法),所以剩余的 \(dp(v,j)\) 也没有贡献了;后面两个和式就是赋值为零的情况。
为了加速运算不妨设 \(\displaystyle f(u,i)=\sum_{j=0}^i dp(u,j)\),那么有
这个柿子可以线段树合并,\(f(v,d_u)\) 在合并外计算即可。这么讲你肯定是听不懂的,但是看代码一定能懂:\(\scr Submission\).
[CEOI 2019] Magic Tree
一些闲话:突然感觉这种闲话格式也挺好的,就像不经意拾起一些生活的碎屑,然后微微惊讶 —— 原来我的闲话里全是 好困、不文明用语 以及 😅😢🥲😵💫😭🥺。那么我今天要说的话就比较典型了 —— md 又感冒了,真的好困啊 🥺🥺🥺。非常烦躁的是教练拿给我一套题做,然后啥也不会直接睡觉,下午来才发现 \(\mathcal T_1\) 自己做过。
首先肯定做子树上的 \(\tt dp\),设 \(dp(u,i)\) 为子树 \(u\) 在时间 \(i\) 之前被断开能得到的最大果汁,转移有:
- 不获取 \(u\) 点的果汁:\(dp(u,i)\gets \sum dp(v,i)\);
- 获取 \(u\) 点的果汁:\(dp(u,t)\gets w_u+\sum dp(v,d_u)\),其中 \(d_u\leqslant t\).
这两种操作需要取 \(\max\),可以考虑线段树合并,合并方式实际上和上文的 [NOI 2022] 命运 一题是一模一样的,用二元组 \((v,\text{tag})\) 维护(注意此时 \(v\) 代表的不是 "时间 \(i\) 之前" 而是 "时间 \(i\)")。时间复杂度 \(\mathcal O(n\log n)\).
再记录一种方法。还是利用 \(\tt dp\) 值不降的性质,我们可以用 map/set 维护 \(\tt dp\) 值的拐点,当然,为了将区间转化成拐点,需要对 \(\tt dp\) 值进行差分。显然每个点至多增加一个拐点,再加上启发式合并就是 \(\mathcal O(n\log n\log k)\) 的。代码量非常小清新。
UOJ - 346 某位歌姬的故事
一些闲话:要中暑了。不想说话。
首先将序列按询问划分成若干个区间,用序列 \(\{a\}\) 表示(其中第 \(i\) 个区间就是 \([a_i,a_{i+1})\))。设 \(\text{up}_i\) 为第 \(i\) 个区间能取得的最大值,只要用所有覆盖此区间的询问 \((l_i,r_i,m_i)\) 的 \(m_i\) 取 \(\min\) 即可。
一个非常重要的 observation 是只有 \(\text{up}_i=m_j\) 的区间才可能满足询问 \(j\) 的最大值条件。考虑若 \(\text{up}_i<m_j\),那么 \(m_j\) 根本取不到;若 \(\text{up}_i>m_j\),那么询问 \(j\) 压根没覆盖这个区间。
于是各个最大值之间都是独立的。枚举最大值 \(v\),选出所有 \(\text{up}_i=v\) 的区间和 \(m_j=v\) 的询问进行 \(\tt dp\),问题就转化成有多少种给区间赋值的方法,使得每个询问都至少包含一个值为 \(v\) 的元素。记 \(dp(i,j)\) 为前 \(i\) 个区间,最后一个取 \(v\) 的元素在区间 \(j\) 的答案。转移有
其中 \(L_i\) 是区间 \(i\) 的长度,\(p_i\) 表示如果区间 \(i\) 没有取到 \(v\) 的元素,往左最多可以等到在 \(p_i\) 中取一个 \(v\)。复杂度 \(\mathcal O(Tq^2)\),精细实现可以做到 \(\mathcal O(Tq\log q)\),\(\tt dp\) 时处理原数组的前缀和即可。
随机 / random
题意简述:唐芯刚学会 st 表。唐芯想用 st 表去维护一个长为 \(n\) 且值域为 \([1, V ]\) 的正整数序列 \(a\) 的区间最小值和最大值。但她突然发现有 \(m\) 次修改,每次修改会给出两个整数 \(x, v\),然后将 \(a_x\) 赋值为 \(v\)。
唐芯并不会用 st 表支持修改,所以她只好退而求其次,如果能维护出每次修改后,st 表上每个区间的极差的平方和,那么就算完成任务。换句话说,记
\[f(l, r) = (\max\{a_l , a_{l+1}, \dots , a_r\} − \min\{a_l , a_{l+1}, \dots , a_r\})^2 \]你需要在每次修改后求出
\[\sum^n_{l=1} \sum^n_{r=l} [r − l + 1 = 2^k ]f(l, r) \]为了体现题目名称,数据保证 \(a_i , v\) 在 \([1, V ]\) 中独立均匀随机,\(x\) 在 \([1, n]\) 中独立均匀随机。
\(1\leqslant n,m\leqslant 5\cdot 10^5,1\leqslant V\leqslant 2\cdot 10^5\).
差点没有成功签到。事实上这题直接暴力递归 st 表进行修改,当递归当 \(\max,\min\) 均未改变时停止即可。原因是在随机数据下,每个值作为区间 \([l,r]\) 的 \(\max/\min\) 的概率为 \(1/(r-l+1)\).
生成树 / tree
题意简述:平面上有 \(n\) 个点,两个点之间的距离定义为曼哈顿距离,求这 \(n\) 个点的最大生成树。
\(n\leqslant 2\cdot 10^6\).
一些闲话:不会 \(\rm prim\) 见祖宗。
考虑 \(\rm prim\),可以发现,只要快速算出当前树与未连接点的距离最大值就可以通过此题。一个非常经典的转化是(喂你这个人事后诸葛亮有什么用啊!)点 \(a,b\) 之间的曼哈顿距离是四种给 \(x_a,x_b,y_a,y_b\) 赋正负号的方案中,带权和最大的方案,这和我们求最大值的目标不谋而合。于是用堆来维护 \(x+y,-x-y,x-y,y-x\) 四种情况即可。复杂度 \(\mathcal O(n\log n)\).
另一种方法仍然基于 \(\rm prim\),只不过将曼哈顿距离转化成切比雪夫距离,它同样也是用 \(\max\) 计算的。然后我们可以贪心地求解 —— 先选出切比雪夫距离最大的一对点 \(a,b\)(不妨设贡献到切比雪夫距离的是 \(x\) 坐标),不妨把 \(a\) 置为 \(\rm prim\) 的起点,于是第一条边就会选择 \((a,b)\),将 \(b\) 加入这棵树。
将所有点按 \(x\) 或按 \(y\) 排序的结果拍成两个序列。如果在按 \(x\) 排序的序列中选边,显然只有可能是 \(x_i\) 到 \(x_a,x_b\) 的最大值,边数为 \(\mathcal O(n)\)(否则不符合 \(\rm prim\));如果在按 \(y\) 排序的序列中选边,同样也只可能是 \(y_i\) 到 \(y_{a'},y_{b'}\) 的最大值(\(a',b'\) 意义同 \(a,b\)),因为从 \(i\) 出发的最大边的另一个端点只可能是 \(a'\) 或 \(b'\),接着再选 \(y\) 就必选 \((a',b')\),然后就又变成了上面的问题。复杂度也是 \(\mathcal O(n\log n)\) 的,但是常数明显优秀一些。