题目链接 Mr. Kitayuta's Colorful Graph
直接讲解法, 主要方法是分情况来做.
怎么分情况呢?
首先对于每个颜色分别处理, 处理的时候就直接用并查集, 把这种颜色能够连接起来的边搞到一个集合里面.
然后用这个颜色的并查集结果来离线更新答案, 更新的时候, 分两种情况,
1. 这个颜色的边个数大于 lim
2. 这个颜色的边小于等于 lim
PS. lim的取值会影响效率, 具体分析见下面
1. 这种情况下, 我们令ans[k]为当前第k个询问的答案, 更新答案的时候就直接遍历每个询问, 如果询问的两个节点在一个并查集内, 则这个询问的答案 + 1, 也就是ans[k] ++;
2. 这种情况下要稍微复杂一点点.
我们需要一个辅助的map , int> M;
初始化的时候遍历 每个询问 q[i][2], 令M[ make_pair(q[i][0], q[i][1]) ] = M[ make_pair(q[i][1], q[i][0]) ] = 0;
然后我们准备把这种情况下的答案保存在M中.
具体的方法是遍历这个颜色的所有边, 取出这些边相连的所有节点放到一个集合S里.
现在再遍历S中的每个节点对(a, b), 如果M.count((a, b)) == 1, 那么 M[(a, b)] ++, M[(b, a)] ++;
最后对于每个询问k, 假设他询问的是节点a和b, 那么其答案就是, ans[k] + M[(a, b)]
效率分析
1. 这种情况下, 每次更新的复杂度是 O(Q), 其中Q是询问的个数
2. 这种情况下, 每次更新的复杂度是 O(lim*lim*log(Q)); lim*lim即是点对的个数, log(Q)是更新M的复杂度.
于是总复杂度就是 Q*A1 + lim*lim*log(Q)*A2, 其中 A1, A2分别为情况1和情况2的个数.
根据分类的定义, 可知A1 <= M / lim.
于是我们可以估计lim的值来计算各种情况下的总效率.
最后可以发现当lim在30左右的时候, 效果不错.
下面是代码
#include
#include
#include
#include
#include
#include
#include
#include