众所周知,货车运输这道题有至少114514种解法,比如树剖,LCA,整体二分,启发式合并等等等等。
我三个月之前学习了启发式合并做法,注意到一片题解中的启发式合并是这么写的:
if(Q[fx].size()>Q[fy].size())swap(fx,fy);
然而并查集的普通启发式合并都是这么写的:
if(siz[fx]>siz[fy])swap(fx,fy);
于是乎,我陷入了深深的疑惑中:这样复杂度能保证吗?
三个月之后,在WC被并查集暴虐的我回到这题的题解区,并且hack掉了它。
这样写的一个问题是如果两边都没有挂询问,那么启发式合并就没用了。考虑到这个性质设计数据,可以设计一条链,然后所有的询问去询问点1点2,所有的点都去和最后一个点连边,边权递增。
代码在运行时会不断地将最后一个点所在集合从大到小增加节点,并且不断访问最后一个点的父亲。
在没有路径压缩的前提下,这样的复杂度是O(n2)的。
// 数据生成器
#include <bits/stdc++.h>
int main() {
int n = 1e5, m = 5e5 - 1, q = 3e5;
// 如果太小的话是能n^2跑过的,于是开到了1e5,正常的nlogn做法是可以通过的。
printf("%d %d\n", n, m);
for (int i = 1; i <= m; ++i) {
printf("%d %d %d\n", n, i, i);
}
printf("%d\n", q);
for (int i = 1; i <= q; ++i) {
printf("%d %d\n", 1, 2);
}
return 0;
}
被我hack掉的题解
加了路径压缩或者正确使用启发式合并都可以通过这组数据。
严格来说,因为需要开大数据,所以实际上并不算是hack