大意:你有30000个队列,第i个队列中只有i
有T个操作,1,把某个队列头接到另一个队列尾。
2,问两个元素之间的距离。
本题主要有三种解法。
①带权并查集。
具体来说就是,并查集维护当前集合的大小,这个点距离代表元(队首)的边数。
然后把合并和路径压缩魔改一下。询问的时候就直接取距离之差。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 3 const int N = 30010; 4 5 int fa[N], sum[N], siz[N]; 6 char str[5]; 7 8 inline int find(int x, int &s) { 9 if(fa[x] == x) { 10 s = 0; 11 return x; 12 } 13 int t = find(fa[x], s); 14 s += sum[x]; 15 sum[x] = s; 16 return fa[x] = t; 17 } 18 19 inline void merge(int x, int y) { 20 int a, b; 21 x = find(x, a); 22 y = find(y, b); 23 fa[x] = y; 24 sum[x] = siz[y]; 25 siz[y] += siz[x]; 26 return; 27 } 28 29 inline int ask(int x, int y) { 30 int a, b; 31 x = find(x, a); 32 y = find(y, b); 33 if(x != y) { 34 return -1; 35 } 36 return (a > b ? a - b : b - a) - 1; 37 } 38 39 int main() { 40 int n; 41 scanf("%d", &n); 42 for(int i = 1; i <= 30000; i++) { 43 fa[i] = i; 44 siz[i] = 1; 45 } 46 for(int i = 1, x, y; i <= n; i++) { 47 scanf("%s%d%d", str, &x, &y); 48 if(str[0] == 'M') { 49 merge(x, y); 50 } 51 else { 52 printf("%d ", ask(x, y)); 53 } 54 } 55 56 return 0; 57 }
②平衡树
这个太暴力了......开30000颗平衡树即可。
③离线(kruskal重构树)
重构的时候把顺序搞一下,然后提出来DFS序,直接回答询问。