推荐:http://blog.csdn.net/dellaserss/article/details/7724401/
int father[maxn], size[maxn]; int fintFatherD(int x) { if (x == father[x]) { return x; } else { return father[x] = findFatherD(father[x]); } }//路径压缩 int findFather(int x) { int p, q; for (p = x; p != father[p]; p = father[p]); for (; x != p; q = father[x], father[x] = p, x = q); return p; }//启发式合并 void init(int n) { for (int i = 1; i <= n; ++ i) { father[i] = i; size[i] = 1; } }//初始化 一开始每个人的父亲都是自己 void joinSets(int a, int b) { a = findFather(a); b = findFather(b); if (size[a] < size[b]) { swap(a, b); } father[b] = a; size[a] += size[b]; }//把元素少的合并到元素大的 只后再把小的爸爸变成大的那个爸爸
例题:维护一个集合,支持插入一个数,查询一个数字前驱
#include <iostream> #include <algorithm> using namespace std; const int maxn = 1000003; int n, m, father[maxn], op[maxn], ans[maxn]; int findRoot(int x) { int p, q; for (p = x; p != father[p]; p = father[p]); for (; x != p; q = father[x], father[x] = p, x = q); return p; } void init(int n) { for (int i = 1; i <= n; ++ i) { father[i] = i - 1; size[i] = 1; } } int main() { cin >> n >> m; init(n); for (int i = 0; i < m; ++ i) { int opt, v; cin >> opt >> v; if (opt == 1) { // 插入 father[v] = v; op[i] = -v; } else { // 查询 op[i] = v; } } for (int i = m - 1; i >= 0; -- i) { if (op[i] < 0) { // 插入,现在要删除它 father[-op[i]] = -op[i] - 1; } else { // 查询前趋 ans[i] = findRoot(op[i] - 1); } } for (int i = 0; i < m; ++ i) { if (ans[i]) { cout << ans[i] << endl; } } }//反向做题 先假设全部插入 之后倒序删除 答案再倒序输出 就是正的了 //op数组记录操作 前驱就是集合中比他小的最大的数