数据结构模板整理

发现把数据结构忘得差不多了,赶紧补了一下
贴几篇讲得不错的博客,不打算再写一遍,骗访问量也要按基本法。
## 主席树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 2e5 + 5;
struct tree {
int l, r;
ll s;
} tr[N << 7];

int n, m, a[N], tot, root[N];
vector<int> v;
#define mid ((l + r) >> 1)
void build(int& p, int l, int r) {
p = ++tot;
if (l == r) {
tr[p].s = 1;
return;
}
build(tr[p].l, l, mid);
build(tr[p].r, mid + 1, r);
}
int clone(int p) {
tr[++tot] = tr[p];
tr[tot].s += 1;
return tot;
}
void modify(int& p, int l, int r, int pos) {
p = clone(p);
if (l == r) return;
if (pos <= mid) modify(tr[p].l, l, mid, pos);
else modify(tr[p].r, mid + 1, r, pos);
}
int query(int x, int y, int l, int r, int k) {
if (l == r) return l;
int kth = tr[tr[x].l].s - tr[tr[y].l].s;
if (kth >= k) return query(tr[x].l, tr[y].l, l, mid, k);
else return query(tr[x].r, tr[y].r, mid + 1, r, k - kth);
}

int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), v.push-back(a[i]);
sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end());
int vn = v.size();
build(root[0], 1, vn);
for (int i = 1; i <= n; i++)
a[i] = lower-bound(v.begin(), v.end(), a[i]) - v.begin() + 1, modify(root[i] = root[i - 1], 1, vn, a[i]);
for (int i = 1; i <= m; i++) {
int l, r, k;
scanf("%d %d %d", &l, &r, &k);
printf("%d\n", v[query(root[r], root[l - 1], 1, vn, k) - 1]);
}
}
## 平衡树 ### splay https://blog.csdn.net/Clove-unique/article/details/50630280

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
const int maxn = 1000019, inf = 1e9;
int tot, root, size[maxn], cnt[maxn], dat[maxn], val[maxn], ch[maxn][2];
int New(int v) {
val[++tot] = v;
dat[tot] = rand();
cnt[tot] = 1;
size[tot] = 1;
return tot;
}
void pushup(int v) { size[v] = size[ch[v][0]] + size[ch[v][1]] + cnt[v]; }
void rotate(int &id, int d) {
int tmp = ch[id][d ^ 1];
ch[id][d ^ 1] = ch[tmp][d];
ch[tmp][d] = id;
id = tmp;
pushup(ch[id][d]), pushup(id);
}
void insert(int &id, int v) {
if (!id) {
id = New(v);
return;
}
if (val[id] == v) {
cnt[id]++;
} else {
int d = val[id] > v ? 0 : 1;
insert(ch[id][d], v);
if (dat[ch[id][d]] > dat[id])
rotate(id, d ^ 1);
}
pushup(id);
}
void remove(int &id, int v) {
if (!id)
return;
if (val[id] == v) {
if (cnt[id] > 1) {
cnt[id]--;
pushup(id);
return;
}
if (ch[id][1] || ch[id][0]) {
if (!ch[id][0] || dat[ch[id][1]] > dat[ch[id][0]]) {
rotate(id, 0);
remove(ch[id][1], v);
} else {
rotate(id, 1);
remove(ch[id][0], v);
}
} else
id = 0;
pushup(id);
}
v < val[id] ? remove(ch[id][0], v) : remove(ch[id][1], v);
pushup(id);
}
int getrank(int id, int k) {
if (!id)
return 0;
if (val[id] == k)
return size[ch[id][0]] + 1;
else if (k < val[id])
return getrank(ch[id][0], k);
else
return size[ch[id][0]] + cnt[id] + getrank(ch[id][1], k);
}
int getval(int id, int rank) {
if (!id)
return inf;
if (rank <= size[ch[id][0]])
return getval(ch[id][0], rank);
else if (rank <= size[ch[id][0]] + cnt[id])
return val[id];
else
return getval(ch[id][1], rank - size[ch[id][0]] - cnt[id]);
}
int getpre(int v) {
int id = root, pre;
while (id) {
if (v > val[id])
pre = val[id], id = ch[id][1];
else
id = ch[id][0];
}
return pre;
}
int getnext(int v) {
int id = root, next;
while (id) {
if (v < val[id])
next = val[id], id = ch[id][0];
else
id = ch[id][1];
}
return next;
}

非旋treap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const int N = 1e6 + 5;
int root, dat[N], siz[N], val[N], ch[N][2], cnt;

int NEW(int v) {
siz[++cnt] = 1;
dat[cnt] = rand();
val[cnt] = v;
return cnt;
}
void pushup(int x) {siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;}
void split(int now, int& x, int& y, int k) {
if (!now) {x = y = 0; return;}
if (val[now] <= k) {
x = now;
split(ch[now][1], ch[now][1], y, k);
pushup(now);
} else {
y = now;
split(ch[now][0], x, ch[now][0], k);
pushup(now);
}
}
int merge(int x, int y) {
if(!x || !y) return x | y;
if(dat[x] < dat[y]) {
ch[x][1] = merge(ch[x][1], y);
pushup(x);
return x;
} else {
ch[y][0] = merge(x, ch[y][0]);
pushup(y);
return y;
}
}
void insert(int v) {
int x, y;
split(root, x, y, v - 1);
root = merge(x, merge(NEW(v), y));
}
void remove(int v) {
int x, y, z;
split(root, x, z, v);
split(x, x, y, v - 1);
y = merge(ch[y][0], ch[y][1]);
root = merge(x, merge(y, z));
}
int kth(int now, int k) {
if (!now) return -19260817;
if (siz[ch[now][0]] + 1 == k) return val[now];
if (siz[ch[now][0]] >= k) return kth(ch[now][0], k);
return kth(ch[now][1], k - siz[ch[now][0]] - 1);
}

旋转treap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
const int N = 1e5 + 5;
const int inf = 1e9;
int root, ch[N][2], val[N], tot[N], cnt, dat[N], size[N];

int New(int v) {
val[++cnt] = v;
dat[cnt] = rand();
size[cnt] = 1;
tot[cnt] = 1;
return cnt;
}
void pushup(int v) { size[v] = tot[v] + size[ch[v][0]] + size[ch[v][1]]; }
void build() {
root = New(-inf);
ch[root][1] = New(inf);
pushup(root);
}
void rotate(int &id, int d) {
int tmp = ch[id][d ^ 1];
ch[id][d ^ 1] = ch[tmp][d];
ch[tmp][d] = id;
id = tmp;
pushup(ch[id][d]);
pushup(id);
}
void insert(int &id, int v) {
if (!id) {
id = New(v);
return;
}
if (val[id] == v) {
tot[id]++;
} else {
int d = v > val[id];
insert(ch[id][d], v);
if (dat[ch[id][d]] > dat[id])
rotate(id, d ^ 1);
}
pushup(id);
}
void remove(int &id, int v) {
if (!id)
return;
else if (val[id] == v) {
if (tot[id] > 1) {
tot[id]--;
pushup(id);
return;
} else if (ch[id][1] || ch[id][0]) {
if (!ch[id][1] || dat[ch[id][0]] > dat[ch[id][1]]) {
rotate(id, 1);
remove(ch[id][1], v);
} else {
rotate(id, 0);
remove(ch[id][0], v);
}
pushup(id);
} else {
id = 0;
pushup(id);
}
return;
}
v > val[id] ? remove(ch[id][1], v) : remove(ch[id][0], v);
pushup(id);
}
int opt3(int id, int x) {
if (!id)
return 0;
if (val[id] == x)
return size[ch[id][0]] + 1;
else if (x < val[id])
return opt3(ch[id][0], x);
else
return tot[id] + size[ch[id][0]] + opt3(ch[id][1], x);
}
int opt4(int id, int x) {
if (!id)
return -1;
if (size[ch[id][0]] >= x)
return opt4(ch[id][0], x);
else if (size[ch[id][0]] + tot[id] >= x)
return val[id];
else
return opt4(ch[id][1], x - tot[id] - size[ch[id][0]]);
}
int getpre(int x) {
int pre, id = root;
while (id) {
if (x > val[id]) {
pre = id;
id = ch[id][1];
} else
id = ch[id][0];
}
return val[pre];
}
int getnxt(int x) {
int nxt, id = root;
while (id) {
if (x < val[id]) {
nxt = id;
id = ch[id][0];
} else
id = ch[id][1];
}
return val[nxt];
}

字符串相关

SA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<bits/stdc++.h>
using namespace std;

const int N = 1e6 + 5;
int n, sa[N], x[N], y[N], c[N], ht[N], m, p; //x->rank y[i]->第i大的第二关键字所对应的第一关键字位置
char s[N];

int main() {
scanf("%s", s + 1);
n = strlen(s + 1); m = 123;
for(int i = 1; i <= n; i++) ++c[x[i] = s[i]];
for(int i = 2; i <= m; i++) c[i] += c[i - 1];
for(int i = n; i >= 1; i--) sa[c[x[i]]--] = i;
for(int w = 1; w <= n; w <<= 1) {
int p = 0;
for(int i = n - w + 1; i <= n; i++) y[++p] = i;
for(int i = 1; i <= n; i++) if(sa[i] > w) y[++p] = sa[i] - w;
for(int i = 1; i <= m; i++) c[i] = 0;
for(int i = 1; i <= n; i++) ++c[x[i]];
for(int i = 2; i <= m; i++) c[i] += c[i - 1];
for(int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i];
swap(x, y); p = 1;
x[sa[1]] = 1;
for(int i = 2; i <= n; i++)
x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + w] == y[sa[i - 1] + w]) ? p : ++p;
if(p == n) break;
m = p;
}
for(int i = 1, k = 0; i <= n; ++i) {
if(k) --k;
while(s[i + k] == s[sa[x[i] - 1] + k]) ++k;
ht[x[i]] = k;
}
for(int i = 1; i <= n; i++) printf("%d ", sa[i]);
putchar('\n');
for(int i = 2; i <= n; i++) printf("%d ", ht[i]);
return 0;
}

kmp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <bits/stdc++.h>
using namespace std;

const int N = 1000086;
int f[N], n;
char s[N], a[N];

int main() {
int ans = 0;
cin >> a + 1 >> s + 1;
f[1] = 0;
int n = strlen(s + 1), j = 0;
for (int i = 2; i <= n; ++i) {
while (s[j + 1] != s[i] && j) j = f[j];
j += s[i] == s[j + 1];
f[i] = j;
}
j = 0;
int k = strlen(a + 1);
for (int i = 1; i <= k; ++i) {
while (s[j + 1] != a[i] && j) j = f[j];
j += s[j + 1] == a[i];
if (j == n) {
ans++;
j = f[j];
}
}
cout << ans << endl;
return 0;
}

动态树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
int n, m, ch[N][2], f[N], s[N], r[N], v[N];

#define lc ch[x][0]
#define rc ch[x][1]

bool noroot(int x) {
return ch[f[x]][1] == x || ch[f[x]][0] == x;
}
void pushup(int x) {
s[x] = s[lc] ^ s[rc] ^ v[x];
}
void pushr(int x) {
swap(lc, rc);
r[x] ^= 1;
}
void pushdown(int x) {
if (r[x]) {
if (lc) pushr(lc);
if (rc) pushr(rc);
r[x] = 0;
}
}
void rotate(int x) {
int y = f[x], z = f[y], k = (ch[y][1] == x), w = ch[x][k ^ 1];
if (noroot(y)) ch[z][y == ch[z][1]] = x;
ch[x][k ^ 1] = y;
ch[y][k] = w;
if (w) f[w] = y;
f[y] = x;
f[x] = z;
pushup(y);
}
void update(int x) {
if (noroot(x)) update(f[x]);
pushdown(x);
}
bool get(int x) {
return ch[f[x]][1] == x;
}
void splay(int x) {
update(x);
for (int fa; fa = f[x], noroot(x); rotate(x)) {
if (noroot(fa)) rotate(get(x) == get(fa) ? fa : x);
}
pushup(x);
}
void access(int x) {
int p;
for (p = 0; x; p = x, x = f[x]) {
splay(x), ch[x][1] = p, pushup(x);
}
}
void makeroot(int x) {
access(x); splay(x);
pushr(x);
}
int findroot(int x) {
access(x);
splay(x);
while (lc) pushdown(x), x = lc;
splay(x);
return x;
}
void split(int x, int y) {
makeroot(x);
access(y);splay(y);
}
void link(int x, int y) {
makeroot(x);
if (findroot(y) != x) f[x] = y;
}
void cut(int x, int y) {
makeroot(x);
if (findroot(y) == x && f[y] == x && !ch[x][0]) {
f[y] = ch[x][1] = 0;
pushup(x);
}
}

int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
while (m--) {
int opt, x, y;
scanf("%d %d %d", &opt, &x, &y);
if (opt == 0) split(x, y), printf("%d\n", s[y]);
if (opt == 1) link(x, y);
if (opt == 2) cut(x, y);
if (opt == 3) splay(x), v[x] = y;
}
return 0;
}

感觉还有好多不会啊
有时间继续更新,是时候该继续学数据结构了...