http://www.lydsy.com/JudgeOnline/problem.php?id=3674
php
Time Limit: 15 Sec Memory Limit: 256 MB
Submit: 4218 Solved: 1557优化
自从zkysb出了可持久化并查集后……
hzwer:乱写能AC,暴力踩标程
KuribohG:我不路径压缩就过了!
ndsf:暴力就能够轻松虐!
zky:……ui
n个集合 m个操做
操做:
1 a b 合并a,b所在集合
2 k 回到第k次操做以后的状态(查询算做操做)
3 a b 询问a,b是否属于同一集合,是则输出1不然输出0
请注意本题采用强制在线,所给的a,b,k均通过加密,加密方法为x = x xor lastans,lastans的初始值为0
0<n,m<=2*10^5加密
5 6
1 1 2
3 1 2
2 1
3 0 3
2 1
3 1 2spa
1
0
1 code
未增强的在3673,可是啥优化都不加也能过.
而后作到这题我才发现并查集有种叫按秩合并的优化...我是傻子吗...
看了第一篇讲解说就是把rank小的接在大的下面
可是rank是什么....
因而我就把编号小的接在大的下面...而后就过了...
但是这和我看到的AC代码好像不同...
而后又看了一篇讲解,发现按秩合并是指把数量小的树接到大的上去,一般是用高度来取代这个数量
...
哦我终于看懂了标程了...
再打一遍,而后发现慢了一倍...
哦仔细想一想按编号来优化也是能够的,除非是8,7,6,5,4,3,2,1这样倒着合并会合出一条链,可是大部分状况下仍是可行的,并且也不须要维护什么东西(大概就是这里节省了时间).
路径压缩...不存在的...怎么可能说我懒得打ip
细节见代码.
get
按编号优化:input
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <ctime> #include <cstdlib> #define pii pair<int, int> #define mp make_pair #define ft first #define sd second #define ls C[rt][0] #define rs C[rt][1] using namespace std; template <typename ty> void read(ty &x) { x = 0; int f = 1; char ch = getchar(); while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x*10 + ch - '0'; ch = getchar(); } x *= f; } template <typename ty> ty Max(ty a, ty b) { return a > b ? a : b; } template <typename ty> ty Min(ty a, ty b) { return a < b ? a : b; } template <typename ty> int Chkmin(ty &a, ty b) { return a > b ? a = b, 1 : 0; } template <typename ty> int Chkmax(ty &a, ty b) { return a < b ? a = b, 1 : 0; } typedef long long LL; typedef double db; const int inf = 0x7fffffff; const int N = 2e5 + 16; int F[N], V[N*20], C[N*20][2], RT[N], P[N]; int n, m, sz, lastans; void build(int &rt, int l, int r) { rt = ++sz; if (l == r) { V[rt] = l; return; } int mid = l + r >> 1; build(C[rt][0], l, mid); build(C[rt][1], mid + 1, r); } int find(int rt) { return F[rt] == rt ? rt : F[rt] = find(F[rt]); } int query(int rt, int l, int r, int pos) { if (l == r) return V[rt]; int mid = l + r >> 1; if (pos <= mid) return query(C[rt][0], l, mid, pos); else return query(C[rt][1], mid + 1, r, pos); } void change(int &now, int pre, int l, int r, int pos, int v) { now = ++sz; C[now][0] = C[pre][0]; C[now][1] = C[pre][1]; if (l == r) { V[now] = v; return; } int mid = l + r >> 1; if (pos <= mid) change(C[now][0], C[pre][0], l, mid, pos, v); else change(C[now][1], C[pre][1], mid + 1, r, pos, v); } int get(int rt, int a) { int tmp = a; while (true) { tmp = query(RT[rt], 1, n, tmp); if (query(RT[rt], 1, n, tmp) != tmp) a = tmp; else return tmp; } } int main () { read(n); read(m); build(RT[0], 1, n); for (int i = 1; i <= m; ++ i) { F[i] = i; int opt, a, b, k; read(opt); if (opt == 1) { read(a); read(b); a ^= lastans, b ^= lastans; int pre = find(i - 1); int tmp1, tmp2; tmp1 = get(pre, a); tmp2 = get(pre, b); if (tmp1 == tmp2) { F[i] = i - 1; continue; } if (tmp1 < tmp2) swap(tmp1, tmp2); change(RT[i], RT[pre], 1, n, tmp1, tmp2); } if (opt == 2) { read(k); k ^= lastans; F[i] = find(k); } if (opt == 3) { F[i] = find(i - 1); read(a); read(b); a ^= lastans, b ^= lastans; int tmp, tmp1, tmp2; tmp1 = get(F[i], a); tmp2 = get(F[i], b); if (tmp1 == tmp2) lastans = 1, printf("1\n"); else lastans = 0, printf("0\n"); } } return 0; }
按秩合并:string
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <ctime> #include <cstdlib> #define pii pair<int, int> #define mp make_pair #define ft first #define sd second #define ls C[rt][0] #define rs C[rt][1] using namespace std; template <typename ty> void read(ty &x) { x = 0; int f = 1; char ch = getchar(); while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x*10 + ch - '0'; ch = getchar(); } x *= f; } template <typename ty> ty Max(ty a, ty b) { return a > b ? a : b; } template <typename ty> ty Min(ty a, ty b) { return a < b ? a : b; } template <typename ty> int Chkmin(ty &a, ty b) { return a > b ? a = b, 1 : 0; } template <typename ty> int Chkmax(ty &a, ty b) { return a < b ? a = b, 1 : 0; } typedef long long LL; typedef double db; const int inf = 0x7fffffff; const int N = 2e5 + 16; int F[N], V[N*20], C[N*20][2], D[N*20], RT[N], P[N]; int n, m, sz, lastans; void build(int &rt, int l, int r) { rt = ++sz; if (l == r) { V[rt] = l; return; } int mid = l + r >> 1; build(C[rt][0], l, mid); build(C[rt][1], mid + 1, r); } int find(int rt) { return F[rt] == rt ? rt : F[rt] = find(F[rt]); } int query(int rt, int l, int r, int pos) { if (l == r) return V[rt]; int mid = l + r >> 1; if (pos <= mid) return query(C[rt][0], l, mid, pos); else return query(C[rt][1], mid + 1, r, pos); } void change(int &now, int pre, int l, int r, int pos, int v) { now = ++sz; C[now][0] = C[pre][0]; C[now][1] = C[pre][1]; if (l == r) { V[now] = v; return; } int mid = l + r >> 1; if (pos <= mid) change(C[now][0], C[pre][0], l, mid, pos, v); else change(C[now][1], C[pre][1], mid + 1, r, pos, v); } int get(int rt, int a) { int tmp = a; while (true) { tmp = query(RT[rt], 1, n, tmp); if (query(RT[rt], 1, n, tmp) != tmp) a = tmp; else return tmp; } } void add(int rt, int l, int r, int pos) { if (l == r) { D[rt] ++; return; } int mid = l + r >> 1; if (pos <= mid) add(C[rt][0], l, mid, pos); else add(C[rt][1], mid + 1, r, pos); } int main () { read(n); read(m); build(RT[0], 1, n); for (int i = 1; i <= m; ++ i) { F[i] = i; int opt, a, b, k; read(opt); if (opt == 1) { read(a); read(b); a ^= lastans, b ^= lastans; int pre = find(i - 1); int tmp1, tmp2; tmp1 = get(pre, a); tmp2 = get(pre, b); if (tmp1 == tmp2) { F[i] = i - 1; continue; } if (D[tmp1] > D[tmp2]) swap(tmp1, tmp2); change(RT[i], RT[pre], 1, n, tmp1, tmp2); if (D[tmp1] == D[tmp2]) add(RT[i], 1, n, tmp2); } if (opt == 2) { read(k); k ^= lastans; F[i] = find(k); } if (opt == 3) { F[i] = find(i - 1); read(a); read(b); a ^= lastans, b ^= lastans; int tmp, tmp1, tmp2; tmp1 = get(F[i], a); tmp2 = get(F[i], b); if (tmp1 == tmp2) lastans = 1, printf("1\n"); else lastans = 0, printf("0\n"); } } return 0; }