题目描述
输入描述 Input Description
第一行包含两个整数N、M。N 表示路口的个数,M 表示道路条数。接下来
M 行,每行两个整数,这两个整数都在1 到N 之间,第i+1 行的两个整数表示第
i 条道路的起点和终点的路口编号。接下来N 行,每行一个整数,按顺序表示每
个路口处的ATM 机中的钱数。接下来一行包含两个整数S、P,S 表示市中心的
编号,也就是出发的路口。P 表示酒吧数目。接下来的一行中有P 个整数,表示
P 个有酒吧的路口的编号。输出描述 Output Description
输出一个整数,表示Banditji 从市中心开始到某个酒吧结束所能抢劫的最多
的现金总数。样例输入 Sample Input
6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1 5
1 4
4 3 5 6样例输出 Sample Output
47数据范围及提示 Data Size & Hint
50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM
机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心
沿着Siruseri 的单向的道路到达其中的至少一个酒吧。
题解
题意还是比较裸的,在环上的ATM机是一定都要抢的。首先是求强连通分量缩点,然后从起点即市中心开始spfa最长路或者DP,目的是求出最终停在每个强连通分量时所抢得的总钱数;然后读入所有酒吧,把有酒吧的强连通分量作为终点,枚举一下取钱数的最大值即可。
然而数据规模使得递归的tarjan算法被卡住了,所以要手动改成非递归。
首先用一个大栈(可以理解成系统栈的替代品,区分递归tarjan用到的小栈)保存当前正在tarjan的点。设当前正在tarjan点x,则先把x入大栈,同时入小栈,标记x的dfn和low的值,并作出相应标记表示x已经入了小栈(就像递归tarjan一样);
其次,开始非递归主过程:
当大栈非空时,从栈顶取出一个元素t,但不要弹栈;
访问t所有出边指向的结点a,若dfn[a]等于0,就把a压入大栈,相当于递归tarjan中的递归调用tarjan(a),然后break掉,进入下文中的“然后”,因为递归tarjan中此时low(a)的值会在递归过程中算出,非递归tarjan中low(a)的值还不知道;
若dfn[a]不等于0,不急,先什么也不干,下文中“然后”会处理;然后,t所有出边都已被遍历,这时,判断t是否是大栈的栈顶;
如果是,则说明t没有进入任何递归过程,即t所有出边指向的点都已经被tarjan完了,这时应该确定low[t]的值;
访问t所有出边指向的结点a,若dfn[a] >