hash的应用

hash可以看成对一串较长信息的压缩和加密,在OI中多用来比较字符串是否相同,然而hash的应用其实可以有很大拓展,比如想要维护全局信息是否处于某种特殊形态,具体来讲,以一个最近题目为例 :

[CSP-S 2022] 星战

题目描述

在这一轮的星际战争中,我方在宇宙中建立了 \(n\) 个据点,以 \(m\) 个单向虫洞连接。我们把终点为据点 \(u\) 的所有虫洞归为据点 \(u\) 的虫洞。

战火纷飞之中这些虫洞很难长久存在,敌人的打击随时可能到来。这些打击中的有效打击可以分为两类:

  1. 敌人会摧毁某个虫洞,这会使它连接的两个据点无法再通过这个虫洞直接到达,但这样的打击无法摧毁它连接的两个据点。
  2. 敌人会摧毁某个据点,由于虫洞的主要技术集中在出口处,这会导致该据点的所有还未被摧毁的虫洞被一同摧毁。而从这个据点出发的虫洞则不会摧毁

注意:摧毁只会导致虫洞不可用,而不会消除它的存在。

为了抗击敌人并维护各部队和各据点之间的联系,我方发展出了两种特种部队负责修复虫洞:

  • A 型特种部队则可以将某个特定的虫洞修复。
  • B 型特种部队可以将某据点的所有损坏的虫洞修复。

考虑到敌人打击的特点,我方并未在据点上储备过多的战略物资。因此只要这个据点的某一条虫洞被修复,处于可用状态,那么这个据点也是可用的。

我方掌握了一种苛刻的空间特性,利用这一特性我方战舰可以沿着虫洞瞬移到敌方阵营,实现精确打击。

为了把握发动反攻的最佳时机,指挥部必须关注战场上的所有变化,为了寻找一个能够进行反攻的时刻。总指挥认为:

  • 如果从我方的任何据点出发,在选择了合适的路线的前提下,可以进行无限次的虫洞穿梭(可以多次经过同一据点或同一虫洞),那么这个据点就可以实现反击
  • 为了使虫洞穿梭的过程连续,尽量减少战舰在据点切换虫洞时的质能损耗,当且仅当只有一个从该据点出发的虫洞可用时,这个据点可以实现连续穿梭
  • 如果我方所有据点都可以实现反击,也都可以实现连续穿梭,那么这个时刻就是一个绝佳的反攻时刻。

总司令为你下达命令,要求你根据战场上实时反馈的信息,迅速告诉他当前的时刻是否能够进行一次反攻

输入格式

输入的第一行包含两个正整数 \(n,m\)

接下来 \(m\) 行每行两个数 \(u,v\),表示一个从据点 \(u\) 出发到据点 \(v\) 的虫洞。保证 \(u \ne v\),保证不会有两条相同的虫洞。初始时所有的虫洞和据点都是完好的。

接下来一行一个正整数 \(q\) 表示询问个数。

接下来 \(q\) 行每行表示一次询问或操作。首先读入一个正整数 \(t\) 表示指令类型:

  • \(t = 1\),接下来两个整数 \(u, v\) 表示敌人摧毁了从据点 \(u\) 出发到据点 \(v\) 的虫洞。保证该虫洞存在且未被摧毁。
  • \(t = 2\),接下来一个整数 \(u\) 表示敌人摧毁了据点 \(u\)。如果该据点的虫洞已全部 被摧毁,那么这次袭击不会有任何效果。
  • \(t = 3\),接下来两个整数 \(u, v\) 表示我方修复了从据点 \(u\) 出发到据点 \(v\) 的虫洞。保证该虫洞存在且被摧毁。
  • \(t = 4\),接下来一个整数 \(u\) 表示我方修复了据点 \(u\)。如果该据点没有被摧毁的虫洞,那么这次修复不会有任何效果。

在每次指令执行之后,你需要判断能否进行一次反攻。如果能则输出 YES 否则输出 NO

输出格式

输出一共 \(q\) 行。对于每个指令,输出这个指令执行后能否进行反攻。

样例 #1

样例输入 #1

3 6
2 3
2 1
1 2
1 3
3 1
3 2
11
1 3 2
1 2 3
1 1 3
1 1 2
3 1 3
3 3 2
2 3
1 3 1
3 1 3
4 2
1 3 2

样例输出 #1

NO
NO
YES
NO
YES
NO
NO
NO
YES
NO
NO

提示

【样例解释 #1】

虫洞状态可以参考下面的图片, 图中的边表示存在且未被摧毁的虫洞:

【样例 #2】

见附件中的 galaxy/galaxy2.ingalaxy/galaxy2.ans

【样例 #3】

见附件中的 galaxy/galaxy3.ingalaxy/galaxy3.ans

【样例 #4】

见附件中的 galaxy/galaxy4.ingalaxy/galaxy4.ans

【数据范围】

对于所有数据保证:\(1 \le n \le 5 \times {10}^5\)\(1 \le m \le 5 \times {10}^5\)\(1 \le q \le 5 \times {10}^5\)

测试点 \(n \le\) \(m \le\) \(q \le\) 特殊限制
\(1 \sim 3\) \(10\) \(20\) \(50\)
\(4 \sim 8\) \({10}^3\) \({10}^4\) \({10}^3\)
\(9 \sim 10\) \(5 \times {10}^5\) \(5 \times {10}^5\) \(5 \times {10}^5\) 保证没有 \(t = 2\)\(t = 4\) 的情况
\(11 \sim 12\) \(5 \times {10}^5\) \(5 \times {10}^5\) \(5 \times {10}^5\) 保证没有 \(t = 4\) 的情况
\(13 \sim 16\) \({10}^5\) \(5 \times {10}^5\) \(5 \times {10}^5\)
\(17 \sim 20\) \(5 \times {10}^5\) \(5\times 10^5\) \(5 \times {10}^5\)

题面摘自洛谷

对于这道题来说,首先一个性质:当且仅当所有点的出度为一时,整个图处于合法状态,此时显然满足连续穿梭,考虑反击,因为每个点都有出度,所以一定可以一直走下去(这时这张图处于的状态大概是一个环加上很多条支路连着这个环)。
每个点的出度都为一是一个很特殊的状态,所以,可以考虑hash,如果把所有点的出度放在一个数组里那么这个数组可以看成一个长度为n的数字串,于是可以用到哈希储存这个状态的hash值。考虑怎么维护,一条边的修改很简单,那么整个据点?可以考虑给每个据点记录一下如果它被摧毁了,它会对hash值造成的影响,然后单点修改时也对这个值修改,然后考虑怎么处理修复整个据点,可以给每个据点备份一个初始时刻摧毁对哈希值的影响,然后初值与修改后的值的差就是已经摧毁的边造成的影响,加上就行了。
example : 共5个点1,2,4向5连了边,那么5的初值为{1,1,0,1,0}的hash值,如果1->5的边摧毁那么就变成{0,1,0,1,0}的hash值,它们差了1号位上的hash。

再来一道
a 和 b 喜欢玩♂游♂戏。
她们在一棵树上玩游戏,已知树有 𝑛𝑛 个点,编号从 1 到 n。第 𝑖 条边有一个正整数边权 wi.
a 和 b 会在这棵树上玩很多次游戏。每次游戏开始前,清楚姐姐都会给定一个点对 (𝑢, 𝑣),(𝑢, 𝑣 为树上不同两点)然后把树上 𝑢 到 𝑣 的路径上所有边的边权拿出来,生成一个数组 𝑆.
a 和 b 轮流在 s 上进行以最优策略进行游戏a 为先手。
游戏的具体规则是这样的:

  1. a 第一次取走一个数。
  2. 记上一个人取走的数的值为 𝑥,当前的人需要从 𝑆 中取走一个不大于 𝑥 的数。不能进行操作的人输。
    清楚姐姐觉得这个游戏十分地有趣,她想知道,在所有可能的初始点对 (𝑢, 𝑣) 中,有多少种情况能使 a 有必胜策略。

这道题首先会有一个结论,手模几下会发现如果只有一个最小值,那么a就取了就赢,如果2个,那取了会输,3个又会赢,所以最小值有奇数个一定会赢,考虑偶数个一定会输吗?显然不如果最小值有两个,次小值有一个那a取次小也会赢,因为他把先手必败态给了b,同理如果次小值有三个也是一样的,于是初步得出结论只要出现奇数个数的数,a直接选最小的那个奇数,那就会赢,应为他会选到最后一个这种数,在b面前的只有偶数,不管选哪个,最后a都会选走最后一个偶数,a就胜利了。
于是我们要做的就是看看u->v的路径上有没有那个数出现奇数次,考虑转化一下发现u->v路径上的数字出现次数奇偶性与u->root->v 相同,因为从lca到root的数算了两次,相当于没算,那么我们记录每个点到根的一个桶的哈希值,如5到根有1个1,2个2,3个3,4个4那么桶就是{1,2,3,4},因为只考虑奇偶性所以可以mod 2,变成{1,0,1,0},把hash值放到一个桶里面,然后搜到一个点看看桶里面有没有相同的有几个,显然哈希值相同意味着桶相同,那么就是全偶数,那么这两个点的路径就会输,统计到答案里,再把这个hash值也放到里面去。

这些大概就是哈希的奇怪用法。

posted @ 2022-10-31 20:14  夏天海里的余  阅读(96)  评论(0)    收藏  举报