题意分析
我们有一个有向图,n个点,m条有向边(每个点的“虫洞”指的是以该点为终点的边)。
敌人打击有两种:
摧毁某条虫洞——只是让这条边不可用,但边仍然存在。
摧毁某个据点——会同时摧毁所有以该点为终点的边(即该点的入边),但不会影响该点出发的边。
我方修复有两种:
修复某条虫洞
修复某个据点—— 修复该点所有被摧毁的入边。
反攻条件:
反击:从任意据点出发,可以无限次虫洞穿梭(即该点在环中或能到达环)。
连续穿梭:当且仅当只有一个从该点出发的虫洞可用时,才能连续穿梭(即每个点的出度 = 1)。
所有据点都满足上述两个条件时,才能反攻。
思路分析
小时候做这题看到数据范围吓哭了,这意味着我们实现的算法只可能是O(n)O(n)O(n),因此必须着手考虑优化
反攻需要整个图弱连通且nnn个节点点出度都为111,即整个图是一个有向且只有nnn个顶点的环(我记得叫单环功能图?),直接按照图论问题思考不太可行……
那我把图论问题转换一下再做不就是了,定义aia_iai 为iii号节点的哈希权值,valival_ivali 为初始状态下,iii号节点所有入边起点的权值和,fif_ifi 为当前状态下,iii号节点所有有效入边起点的权值和,sumsumsum为∑i=1nai\sum_{i=1}^n a_i∑i=1n ai ,cntcntcnt为∑i=1nfi\sum_{i=1}^n f_i∑i=1n fi 。由于使用的是unsigned long longunsigned\ long\ longunsigned long long来随机,所以在5×1055
\times10^55×105范围内哈希冲突的概率极小,基本可以忽略。
当图满足反攻条件时,每个点出度为111,整个图是一个大环(弱连通),那么每个节点的权值aia_iai 会通过它的出边传递给下一个节点,由于是完整的大环,每个权值都会在环中传递一圈,最终cntcntcnt(所有节点入边权值和)正好等于sumsumsum(所有权值总和)。反之,如果图不满足条件(出度不为1或不连通),cntcntcnt就不会等于sumsumsum。
因此我们推出:当cnt=sumcnt = sumcnt=sum时,可以反攻。
对于每个操作,按题目与数组表意修改即可。
AC代码
时间复杂度
O(n+m+q)O(n+m+q)O(n+m+q),可以处理n,m,q<=5×105n, m, q<=5 \times 10^5n,m,q<=5×105的较大数据。