第四次實驗 PKI及SSL協議分析
阿新 • • 發佈:2021-09-27
跳躍表,簡稱跳錶。一種鏈式資料結構,可用於支援平衡樹的操作。
【模板】普通平衡樹
跳錶基於隨機化,每個節點以 \(\frac{1}{2}\) 的概率保留一層,\(\frac{1}{4}\) 機率保留兩層,依次類推。
期望時間複雜度 \(\mathcal{O}(N\log N)\),實際執行不遜於主流平衡樹,且具有碼量小,便於理解的優點。
如果直接開陣列空間複雜度是 \(\mathcal{O}(N\log N)\),使用指標或者變長陣列 vector 的期望空間複雜度是 \(\sum\limits_{i}2^{-i}N=\mathcal{O}(N)\)。本題前者已經足夠。
#define N 100005 #define M 20 struct node{ int val, nxt[M], sum[M]; }a[N]; #define nt(x, p) a[x].nxt[p] int idx, u[M]; inline int g(){int s = 0;while(s + 1 < M && (rand() & 4))s ++;return s;} void ask(int x){ int p = M - 1, w = 0; while(p >= 0){ while(nt(w, p) && a[nt(w, p)].val < x)w = nt(w, p); u[p--] = w; } } void ins(int x){ ask(x); int p = 0; if(a[nt(u[0], 0)].val == x){ while(p < M){ if(a[nt(u[p], p)].val == x)a[nt(u[p], p)].sum[p] ++; else a[u[p]].sum[p]++; p++; } } else{ int q = g(), w = nt(u[0], 0); a[++idx].sum[0] = 1, a[idx].val = x; nt(idx, 0) = w, nt(u[0], 0) = idx; rep(i, 1, q){ a[idx].sum[i] = a[idx].sum[i - 1]; while(w != nt(u[i], i))a[idx].sum[i] += a[w].sum[i - 1], w = nt(w, i - 1); nt(idx, i) = nt(u[i], i), nt(u[i], i) = idx, a[u[i]].sum[i] -= a[idx].sum[i] - 1; } rep(i, q + 1, M - 1)a[u[i]].sum[i] ++; } } void del(int x){ ask(x); int p = 0; bool flag = a[nt(u[0], 0)].sum[0] == 1; while(p < M){ if(a[nt(u[p], p)].val == x){ if(flag) a[u[p]].sum[p] += a[nt(u[p], p)].sum[p] - 1, nt(u[p], p) = a[nt(u[p], p)].nxt[p]; else a[nt(u[p], p)].sum[p]--; } else a[u[p]].sum[p]--; p++; } } int Rank(int x){ int p = M - 1, w = 0, ans = 0; while(p >= 0){ while(nt(w, p) && a[nt(w, p)].val < x)ans += a[w].sum[p], w = nt(w, p); p--; } return ans + a[w].sum[0]; } int get(int k){ int p = M - 1, w = 0; while(p >= 0){ while(k >= a[w].sum[p])k -= a[w].sum[p], w = nt(w, p); p--; } return a[w].val; } int Nxt(int x){ ask(x); int p = nt(u[0], 0); if(a[p].val == x)return a[nt(p, 0)].val; return a[p].val; } int Pre(int x){ ask(x);return a[u[0]].val; } int main() { srand(time(0)); int T = read(); a[0].val = inf_; rep(i, 0, M - 1)a[0].sum[i] = 1; while(T--){ int op = read(), x = read(); if(1 == op)ins(x); else if(2 == op)del(x); else if(3 == op)printf("%d\n", Rank(x)); else if(4 == op)printf("%d\n", get(x)); else if(5 == op)printf("%d\n", Pre(x)); else printf("%d\n", Nxt(x)); } return 0; }
【模板】普通平衡樹(資料加強版)
同上,實測速度優於主流平衡樹,但是第四個點被卡空間。
第四個點全是插入可以特判。
嘗試了下 vector 發現空間常數巨大反而是負優化。
指標以後再補
#define N 1000005 #define M 12 struct node{ int val, nxt[M], sum[M]; }a[N]; #define nt(x, p) a[x].nxt[p] int idx, u[M]; inline int g(){int s = 0;while(s + 1 < M && (rand() & 3) == 3)s ++;return s;} void ask(int x){ int p = M - 1, w = 0; while(p >= 0){ while(nt(w, p) && a[nt(w, p)].val < x)w = nt(w, p); u[p--] = w; } } void ins(int x){ ask(x); int p = 0; if(a[nt(u[0], 0)].val == x){ while(p < M){ if(a[nt(u[p], p)].val == x)a[nt(u[p], p)].sum[p] ++; else a[u[p]].sum[p]++; p++; } } else{ int q = g(), w = nt(u[0], 0); a[++idx].sum[0] = 1, a[idx].val = x; nt(idx, 0) = w, nt(u[0], 0) = idx; rep(i, 1, q){ a[idx].sum[i] = a[idx].sum[i - 1]; while(w != nt(u[i], i))a[idx].sum[i] += a[w].sum[i - 1], w = nt(w, i - 1); nt(idx, i) = nt(u[i], i), nt(u[i], i) = idx, a[u[i]].sum[i] -= a[idx].sum[i] - 1; } rep(i, q + 1, M - 1)a[u[i]].sum[i] ++; } } void del(int x){ ask(x); int p = 0; bool flag = a[nt(u[0], 0)].sum[0] == 1; while(p < M){ if(a[nt(u[p], p)].val == x){ if(flag) a[u[p]].sum[p] += a[nt(u[p], p)].sum[p] - 1, nt(u[p], p) = a[nt(u[p], p)].nxt[p]; else a[nt(u[p], p)].sum[p]--; } else a[u[p]].sum[p]--; p++; } } int Rank(int x){ int p = M - 1, w = 0, ans = 0; while(p >= 0){ while(nt(w, p) && a[nt(w, p)].val < x)ans += a[w].sum[p], w = nt(w, p); p--; } return ans + a[w].sum[0]; } int get(int k){ int p = M - 1, w = 0; while(p >= 0){ while(k >= a[w].sum[p])k -= a[w].sum[p], w = nt(w, p); p--; } return a[w].val; } int Nxt(int x){ ask(x); int p = nt(u[0], 0); if(a[p].val == x)return a[nt(p, 0)].val; return a[p].val; } int Pre(int x){ ask(x);return a[u[0]].val; } int main() { srand(time(0)); int n = read(), T = read(); a[0].val = inf_; rep(i, 0, M - 1)a[0].sum[i] = 1; rp(i, n)ins(read()); int lastans = 0, xorsum = 0; while(T--){ if(idx >= 900000){puts("0");return 0;} int op = read(), x = read() ^ lastans; if(1 == op)ins(x); else if(2 == op)del(x); else { if(3 == op)lastans = Rank(x); else if(4 == op)lastans = get(x); else if(5 == op)lastans = Pre(x); else lastans = Nxt(x); xorsum ^= lastans; } } cout << xorsum << endl; return 0; }