数据结构复习1
Posted candy99
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构复习1相关的知识,希望对你有一定的参考价值。
数据结构复习1
主席树
细节:
- x和y是节点编号,所以是root[i]不是i
- 每次复制原来的节点,再新建
线段树
标记
多个标记考虑优先级
满足区间加法就可以用线段树
平衡树
Treap
满足平衡树的性质,同时随机附加域维护一个小根堆
- rturn,左儿子成为根 c=t[x].l t[x].l=t[c].r t[c].r=x
- lturn,右儿子成为根
- 插入
- !x 新建节点
- 判断向哪走,递归结束时维护堆性质
- 删除
- !x 返回
- 判断有几个,1个的话左右儿子谁继承他。注意先旋转再删自己的技巧
- 还不到就走
- rnk, kth, pre, suf
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define lc t[x].l
#define rc t[x].r
const int N = 1e5+5;
inline int read() {
int x=0, f=1; char c=getchar();
while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
return x*f;
}
struct meow {
int x, l, r, v, w, size, rnd;
meow() {}
meow(int a) {l=r=0; v=a; w=size=1; rnd=rand();}
} t[N];
int sz, root;
inline void update(int x) {
t[x].size = t[lc].size + t[rc].size + t[x].w;
}
inline void rturn(int &x) {
int c = lc; lc = t[c].r; t[c].r = x;
t[c].size = t[x].size; update(x); x=c;
}
inline void lturn(int &x) {
int c = rc; rc = t[c].l; t[c].l = x;
t[c].size = t[x].size; update(x); x=c;
}
void insert(int &x, int v) {
if(!x) {
x = ++sz;
t[x] = meow(v);
} else {
t[x].size++;
if(v == t[x].v) t[x].w++;
else if(v < t[x].v) {
insert(lc, v);
if(t[lc].rnd < t[x].rnd) rturn(x);
} else {
insert(rc, v);
if(t[rc].rnd < t[x].rnd) lturn(x);
}
}
}
void erase(int &x, int v) {
if(!x) return;
if(v == t[x].v) {
if(t[x].w > 1) t[x].w--, t[x].size--;
else if(!lc || !rc) x = lc|rc;
else if(t[lc].rnd < t[rc].rnd) rturn(x), erase(x, v);
else lturn(x), erase(x, v);
} else {
t[x].size--;
if(v < t[x].v) erase(lc, v);
else erase(rc, v);
}
}
int rnk(int x, int v) {
if(!x) return 0;
if(v == t[x].v) return t[lc].size + 1;
else if(v < t[x].v) return rnk(lc, v);
else return t[lc].size + t[x].w + rnk(rc, v);
}
int kth(int x, int k) {
if(!x) return 0;
if(k <= t[lc].size) return kth(lc, k);
else if(k <= t[lc].size + t[x].w) return t[x].v;
else return kth(rc, k - t[lc].size - t[x].w);
}
int ans = 0;
void pre(int x, int v) {
if(!x) return;
if(t[x].v < v) ans = x, pre(rc, v);
else pre(lc, v);
}
void suf(int x, int v) {
if(!x) return;
if(t[x].v > v) ans = x, suf(lc, v);
else suf(rc, v);
}
int n;
int main() {
freopen("in", "r", stdin);
srand(2333);
n = read();
for(int i=1; i<=n; i++) {
int c = read(), x = read();
if(c == 1) insert(root, x);
else if(c == 2) erase(root, x);
else if(c == 3) printf("%d
", rnk(root, x));
else if(c == 4) printf("%d
", kth(root, x));
else if(c == 5) pre(root, x), printf("%d
", t[ans].v);
else if(c == 6) suf(root, x), printf("%d
", t[ans].v);
}
}
Splay
伸展树。插入、查询后将该节点splay到根
- rotate 将x转到父亲的位置 注意fa信息的维护
- splay 将x伸展到父亲为tar的位置 共线时先转父亲
- 插入
- !root 新节点是根
- 已存在v
- 不存在v,记录last信息,找到后处理
- 寻找 将v找到并splay到根
- 删除
- splay到根
- 多个
- 没有儿子,一个儿子
- 两个儿子,找左子树最大节点,splay到左儿子,右儿子接在左儿子右边
- rnk, kth, pre, suf
- 区间操作 [l,r] 将l-1对应的节点splay到左子树,r+1对应的节点splay到柚子树,r+1的左儿子子树就是区间[l,r]
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define lc t[x].ch[0]
#define rc t[x].ch[1]
#define pa t[x].fa
const int N = 1e5+5;
inline int read() {
int x=0, f=1; char c=getchar();
while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
return x*f;
}
struct meow {
int ch[2], fa, v, w, size;
meow() {}
meow(int a) {ch[0]=ch[1]=fa=0; v=a; w=size=1;}
} t[N];
int sz, root;
inline void update(int x) {
t[x].size = t[lc].size + t[rc].size + t[x].w;
}
inline int wh(int x) {return t[pa].ch[1] == x;}
inline void rotate(int x) {
int f = t[x].fa, g = t[f].fa, c = wh(x);
if(g) t[g].ch[wh(f)] = x; t[x].fa = g;
t[f].ch[c] = t[x].ch[c^1]; t[t[f].ch[c]].fa = f;
t[x].ch[c^1] = f; t[f].fa = x;
update(f); update(x);
}
inline void splay(int x, int tar) {
for(; pa != tar; rotate(x))
if(t[pa].fa != tar) rotate(wh(x) == wh(pa) ? pa : x);
if(!tar) root = x;
}
void insert(int v) {
if(!root) {root = ++sz; t[root] = meow(v); return;}
int x = root, last = 0;
while(x) {
if(v == t[x].v) {
t[x].w++; t[x].size++; splay(x, 0); return;
}
last = x;
if(v < t[x].v) x = lc;
else x = rc;
}
x = ++sz; t[x] = meow(v);
if(v < t[last].v) t[last].ch[0] = x;
else t[last].ch[1] = x;
t[x].fa = last;
splay(x, 0);
}
int find(int v) {
int x = root;
while(x) {
if(v == t[x].v) {splay(x, 0); break;}
else if(v < t[x].v) x = lc;
else x = rc;
}
return x;
}
void erase(int v) {
int x = find(v);
if(t[x].w > 1) t[x].w--, t[x].size--;
else if(!lc && !rc) root = 0;
else if(!rc) t[lc].fa = 0, root = lc;
else if(!lc) t[rc].fa = 0, root = rc;
else {
int _ = lc;
while(t[_].ch[1]) _ = t[_].ch[1];
splay(_, x);
t[_].ch[1] = rc; t[rc].fa = _;
t[_].fa = 0; root = _;
update(root);
}
}
int rnk(int v) {
int x = root, lsize = 0;
while(x) {
if(v == t[x].v) {
int ans = lsize + t[lc].size + 1;
splay(x, 0);
return ans;
}
else if(v < t[x].v) x = lc;
else lsize += t[lc].size + t[x].w, x = rc;
}
return -1;
}
int kth(int k) {
int x = root;
while(x) {
if(k <= t[lc].size) x = lc;
else if(k <= t[lc].size + t[x].w) return t[x].v;
else k -= t[lc].size + t[x].w, x = rc;
}
return -1;
}
int pre(int v) {
int x = root, ans = 0;
while(x) {
if(t[x].v < v) ans = x, x = rc;
else x = lc;
}
return ans;
}
int suf(int v) {
int x = root, ans = 0;
while(x) {
if(t[x].v > v) ans = x, x = lc;
else x = rc;
}
return ans;
}
int n, ans;
int main() {
freopen("in", "r", stdin);
n = read();
for(int i=1; i<=n; i++) {
int c = read(), x = read();
if(c == 1) insert(x);
else if(c == 2) erase(x);
else if(c == 3) printf("%d
", rnk(x));
else if(c == 4) printf("%d
", kth(x));
else if(c == 5) ans = pre(x), printf("%d
", t[ans].v);
else if(c == 6) ans = suf(x), printf("%d
", t[ans].v);
}
}
以上是关于数据结构复习1的主要内容,如果未能解决你的问题,请参考以下文章