####Description
在遥远的S星系中一共有N个星球,编号为1…N。其中的一些星球决定组成联盟,以方便相互间的交流。
但是,组成联盟的首要条件就是交通条件。初始时,在这N个星球间有M条太空隧道。每条太空隧道连接两个星球,使得它们能够相互到达。若两个星球属于同一个联盟,则必须存在一条环形线路经过这两个星球,即两个星球间存在两条没有公共隧道的路径。
为了壮大联盟的队伍,这些星球将建设P条新的太空隧道。这P条新隧道将按顺序依次建成。一条新轨道建成后,可能会使一些星球属于同一个联盟。你的任务是计算出,在一条新隧道建设完毕后,判断这条新轨道连接的两个星球是否属于同一个联盟,如果属于同一个联盟就计算出这个联盟中有多少个星球。
####Input
第1行三个整数N,M和P,分别表示总星球数,初始时太空隧道的数目和即将建设的轨道数目。
第2至第M+1行,每行两个整数,表示初始时的每条太空隧道连接的两个星球编号。
第M+2行至第M+P+1行,每行两个整数,表示新建的太空隧道连接的两个星球编号。这些太空隧道按照输入的顺序依次建成。
####Output
输出共P行。如果这条新的太空隧道连接的两个星球属于同一个联盟,就输出一个整数,表示这两个星球所在联盟的星球数。如果这条新的太空隧道连接的两个星球不属于同一个联盟,就输出”No”(不含引号)。
####Sample Input
输入1:
3 2 1
1 2
1 3
2 3
输入2:
5 3 4
1 2
4 3
4 5
2 3
1 3
4 5
2 4
####Sample Output
输出1:
3
输出2:
No
3
2
5
####Data Constraint
对于10%的数据有1≤N,M,P≤100;
对于40%的数据有1≤N,M,P≤2000;
对于100%的数据有1≤N,M,P≤200000。
####Hint
###题解
对于本题,我们要做的就是对新加的边的两个端点进行分析。
很明显,如果这两个点已经处于同一个强连通分量中,就不必改变,如果这两个点不在同一个强连通分量中,可能有两种情况:
1、这条边使得那两个点处于同一强连通分量中。
2、这条边使得两个点联通,即当前通的一个桥。
对于第二种情况,可以预先处理,然而对于第一种情况又该如何处理呢?
很明显,如果这条边使得原本不在同一强连通分量的两个点处在了统一的强连通分量,则在添加这条边之前这两个点之间有且仅有唯一一条路径相连。
这让我们想起了一种特殊的图——树!
树中任意的两个节点之间有且仅有唯一一条路径相连。那么如何将原图转化为一棵树呢?
实际上我们可以将上面所说的情况 2 的边看作为一条树边,很明显一个包含N 个节点的图最多含有 N-1 个桥。将这些桥预先计算出来后,我们可以构造一个树(或森林)。
对于一棵树,若树上的两个点不是父子关系,而它们之间新添加了一条边,那么这条边可能形成新的强连通分量,由树的性质,添加过新的边之后,这两个点和这两个点所在路径上所有的点一定处于一个强连通分量之中。
对于给定的两个节点,我们可以先找到其最近公共祖先(lca),在将 lca 到这两个点的路径上所有的点合并为同一个强连通分量。这里可以用并查集维护。初始时每个节点指向自己,在合并时,将指针指向所合并的 lca。
如上图,当我们
新添加红色标出的那条边时,可以将所有绿色的点指向 lca,也就是蓝色的点。
在维护并查集时,要注意并查集元素大小的累加。
接下来的问题就是如何找到两个点的最近公共祖先呢?最近公共祖先有一个特点:它在树中的高度 H 不大于所要查询的那两个节点在树中的高度。我们可以迭代完成查询 lca 的过程。
例如:给定两个点 X,Y,我们得到这两个点在树中的高度,接下来如果 Hx>=Hy 我们就将 X 替换为它的父亲(这里的父亲指缩点后的父亲),否则就将 Y 替换为它的父亲,直到 X=Y 为止。这期间,我们可以顺便完成并查集的合并操作。
显然,一开始我们还需进行对每个节点 H 的计算,这里推荐用 BFS(DFS可能会爆栈)更为合适。需要注意的是,给定的图未必联通,所以构成的可能不是树而是森林。
下面让我们总结这个算法的流程:
第一步:依据输入数据构造出树或森林,这里可以用强连通分量找桥也可以选用并查集。
第二步:BFS 计算出每个节点 H 的大小。
第三步:依次处理新加的 P 条边,维护并查集完成 lca 查询及缩点操作。
时间复杂度:O(N+M+P) 期望得分:100 分。
涉及内容: 1.图与树的转化
2.并查集、强连通分量算法
3.宽度优先搜索
4.数据的预处理与再处理。