做题笔记✍

AtCoder

Others

Pakencamp 2022 Day2 H

2023.6.30 Problem Link

\(n\) 个帮派在打架,每个帮派有一个大小 \(a_i\),每相邻两个帮派有一个仇恨度 \(b_i\)。现在有 \(Q\) 次单点修改 \(a_i\) 或者 \(b_i\),然后给出区间 \([l,r]\),询问区间 \([l,r]\) 内的帮派打架后最后剩下的那个帮派是谁。
打架的规则是:每次选出 \(b_i\) 最大的相邻两个帮派打一架,人数较多的帮派获胜(相同则编号较小的获胜),然后败者全部加入胜者的帮派。


一个经典的值域减半思想 + 一个经典的双端点二分思想。

  1. 时光倒流

这个操作并不优美,考虑时光倒流,每次找到 \(b_i\) 最小的相邻帮派,然后把左边和右边较小的扔掉。

  1. 值域减半

注意到我们扔掉的是较小的一半,这意味着中间较大的一半会留着。于是就有这么一个类似于“不变量”的东西,只有区间的和减半的时候才会改变。如果我们每次可以“快进”到“不变量”改变的时候,就可以在 \(\log V\) 乘上快进一次的时间内解决问题。
设当前区间和为 \(X\),则我们希望找出缩小后的区间 \(\le X/2\) 的最早时刻。然后注意到,如果令 \(p\) 为最小的满足 \(\mathrm{sum}[l,p]\ge X/2\) 的点,那么不断缩小中的 \([l,r]\) 会始终包含 \(p\),直至下一步就会 \(\le X/2\) 为止,然后暴力减半一步。

  1. 双端点二分

我们开始“二分”这个区间 \([u,d]\)。一个区间怎么二分呢?令 \(u\) 当前的区间范围为 \([l_u,r_u]\)\(d\) 当前的区间范围为 \([l_d,r_d]\),我们希望每次“二分”将 \([l_u,r_u]\) 或者 \([l_d,r_d]\) 缩小一半。考虑找出 \(mid_u\)\(mid_v\),然后分 \(\mathrm{sum}[mid_u,mid_v]\) 讨论。

如果 \(\mathrm{sum}[mid_u,mid_v]\le X/2\),此时不妨设 \(\min[mid_u,r_u]<\min[l_d,mid_d]\),那么如果在 \([l_d,mid_d]\) 中砍了一刀,那 \([mid_u,r_u]\) 之间也一定被砍了一刀,那 \(d\in[l_d,mid_d]\) 一定不合法,于是 \(d\) 可以往右边递归;

如果 \(\mathrm{sum}[mid_u,mid_v]> X/2\),此时不妨设 \(\min[l_u,mid_u]<\min[mid_d,r_d]\),那么如果在 \([l_u,mid_u]\) 中砍了一刀,那 \([mid_d,r_d]\) 之间也一定被砍了一刀,那 \(d\in[l_u,mid_u]\) 一定不合法(有些边界),于是 \(u\) 可以往右边递归。

无论如何,\(u,d\) 一定有一个可以往一边递归,所以这部分时间复杂度 \(O(\log n)\)

总时间复杂度 \(O(n\log V\log n)\)

Loj

Loj6669 Nauuo and Binary Tree

2023.7.3 Problem Link

交互库有一棵 \(n\) 个点的二叉树,你每次可以询问两个点之间的距离,猜出这棵二叉树。\(n\le 3000\),询问次数上限 \(30000\)


首先给你距离一定是先把每个点的深度问出来,确定一个大致的考虑顺序。

然后我们开始仔细思考“距离”这个条件怎么用。发现询问两个未知的点之间的距离没啥用,询问两个已知的点很蠢,于是只可能询问未知点和已知点之间的距离。

假设未知点是 \(u\),已知点是 \(v\),那我们就得到了 \(dep[\mathrm{lca}(u,v)]\)。进一步,\(v\) 已知,这意味着我们可以知道 \(\mathrm{lca}(u,v)\) 是哪个。

走到这一步这道题就很明朗了。我们希望进行一个类似于二分的过程,结合二叉树这一点,我们可以将考虑范围缩小到链往下的一棵子树内。这不就是重剖吗?做完了。

具体地,对于每个新点,对已知的树进行重剖,找到当前根所在重链的底端,询问新节点和它的距离,并改变当前节点。次数为 \(\sum_{i=1}^n \log i=O(n\log n)\),并且常数很小,很符合题目限制。

Uoj

Uoj618 【JOISC2021】聚会 2

2023.7.3 Problem Link

给定一棵 \(n\) 个点的树,对于一个点集 \(S\),定义 \(f(u,S)\)\(\min_u \sum_{v\in S} \mathrm{dis}(u,v)\)\(g(S)\) 为使得 \(f(u,S)\) 取到最小值的 \(u\) 个数。对 \(1\le i\le n\),求 \(\min_{|S|=i} g(S)\)


首先当 \(i\) 是奇数的时候答案一定为 \(1\),否则答案一定是一条链。把思路转移到这条链上。

考虑这条链上的点有什么性质,就是这条链的端点满足它指向链外的子树大小 \(\ge i/2\),然后动态加新满足条件的点维护整棵树的直径即可。

但是发现我们并不知道一个点往外指的子树是哪条,怎么办呢?

思路 1:发现点不好考虑,转到边上。发现一条边在链上需要它两边的子树中较小的那个 \(\ge i/2\) 即可,于是把加点变成加边即可。

思路 2:考虑点还是可以的。发现对于链的端点,链那端的子树大小一定 \(\ge i/2\),所以把一个点的权值定为除去最大子树以外的子树和即可。

Yandex

2023.6.30 Problem Link

定义一个串 \(S\) 是好的,当且仅当 \(S\) 可以不断消去相邻两个相同字符直至消空。给定一个长为 \(n\) 的字符串 \(s\),求有多少个有序对 \((i,j)\) 满足 \(s_i\neq s_j\) 且交换 \(s_i,s_j\)\(s\) 是好的。


技巧:镜面对称矩阵哈希,\(A^2=I\)

考虑哈希,给每种字符赋一个特殊的矩阵,使得相邻两个相同的字符乘起来可以变成 \(I\) 然后消掉。后面只需要一个猫树分治和一个哈希表即可,不是这里的重点。这里只提怎样构造这么一个矩阵。

考虑三维空间中的镜面对称。在三维空间中随一个过原点的平面 \(Ax+By+Cz=0\),那么点 \((a,b,c)\) 的对称点是形如三维向量 \((a,b,c)\) 左乘上一个矩阵 \(A\),由于 \((a,b,c)\) 的对称点的对称点一定是自己,所以 \(AA=I\) 一定成立。

考虑怎么算平面 \(Ax+By+Cz=0\) 对应的矩阵 \(A\)。平面 \(Ax+By+Cz=0\) 的法向量为 \((A,B,C)\),所以点 \((a,b,c)\) 在平面上的投影一定形如 \((At+a,Bt+b,Ct+c)\),代入得 \((A^2+B^2+C^2)t+Aa+Bb+Cc=0\)

解得 \(t\) 之后可以很容易求出 \((a,b,c)\) 的对称点,矩阵即可求出。

posted @ 2023-06-30 16:31  CharlieVinnie  阅读(30)  评论(0编辑  收藏  举报