Loading

【笔记】跳跃表

跳跃表,简称跳表。一种链式数据结构,可用于支持平衡树的操作。

【模板】普通平衡树

跳表基于随机化,每个节点以 \(\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;
}
posted @ 2021-10-02 15:55  7KByte  阅读(55)  评论(0编辑  收藏  举报