这里对开发中常用的数据结构做了补充
包括但不限于treap树,并查集,树状数组等

优先队列

UVA11997
UVA11997

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
//
// main.cpp
// UVA11997
//
// Created by zhangmin chen on 2019/7/8.
// Copyright © 2019 zhangmin chen. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
#include <cmath>

using namespace std;
typedef long long llong;
typedef set<int>::iterator ssii;

const int maxn = 750 + 10;

#define Cmp(a, b) memcmp(a, b, sizeof(b))
#define Cpy(a, b) memcpy(a, b, sizeof(b))
#define Set(a, v) memset(a, v, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define _forS(i, l, r) for(set<int>::iterator i = (l); i != (r); i++)
#define _rep(i, l, r) for(int i = (l); i <= (r); i++)
#define _for(i, l, r) for(int i = (l); i < (r); i++)
#define _forDown(i, l, r) for(int i = (l); i >= r; i--)
#define debug_(ch, i) printf(#ch"[%d]: %d\n", i, ch[i])
#define debug_m(mp, p) printf(#mp"[%d]: %d\n", p->first, p->second)
#define debugS(str) cout << "dbg: " << str << endl;
#define debugArr(arr, x, y) _for(i, 0, x) { _for(j, 0, y) printf("%c", arr[i][j]); printf("\n"); }
#define _forPlus(i, l, d, r) for(int i = (l); i + d < (r); i++)

int A[maxn][maxn];
int n;

void init() {
Set(A, 0);
}

class Node {
public:
int S, b;
Node(int _S = 0, int _b = 0) : S(_S), b(_b) {}

bool operator< (const Node& rhs) const {
return S > rhs.S;
}
};

void _merge(int* A, int* B, int* C, int n) {
priority_queue<Node> pq;
_for(i, 0, n) pq.push(Node(A[i] + B[0], 0));

_for(i, 0, n) {
Node x = pq.top();
pq.pop();

C[i] = x.S;
if(x.b + 1 < n) pq.push(Node(x.S - B[x.b] + B[x.b+1], x.b+1));
}
}

int main() {
freopen("input.txt", "r", stdin);
while (scanf("%d", &n) == 1) {
init();
_for(i, 0, n) _for(j, 0, n) scanf("%d", &A[i][j]);
_for(i, 0, n) sort(A[i], A[i] + n);

_for(i, 1, n) _merge(A[0], A[i], A[0], n);

printf("%d", A[0][0]);
_for(i, 1, n) printf(" %d", A[0][i]);

printf("\n");
}
}

并查集按秩压缩

LA3027
LA3027

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
//
// main.cpp
// LA3027
//
// Created by zhangmin chen on 2019/7/10.
// Copyright © 2019 zhangmin chen. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
#include <cmath>

using namespace std;
typedef long long llong;
typedef set<int>::iterator ssii;

const int maxn = 20000 + 10;

#define Cmp(a, b) memcmp(a, b, sizeof(b))
#define Cpy(a, b) memcpy(a, b, sizeof(b))
#define Set(a, v) memset(a, v, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define _forS(i, l, r) for(set<int>::iterator i = (l); i != (r); i++)
#define _rep(i, l, r) for(int i = (l); i <= (r); i++)
#define _for(i, l, r) for(int i = (l); i < (r); i++)
#define _forDown(i, l, r) for(int i = (l); i >= r; i--)
#define debug_(ch, i) printf(#ch"[%d]: %d\n", i, ch[i])
#define debug_m(mp, p) printf(#mp"[%d]: %d\n", p->first, p->second)
#define debugS(str) cout << "dbg: " << str << endl;
#define debugArr(arr, x, y) _for(i, 0, x) { _for(j, 0, y) printf("%c", arr[i][j]); printf("\n"); }
#define _forPlus(i, l, d, r) for(int i = (l); i + d < (r); i++)

int pa[maxn], d[maxn];
void initSet() {
_for(i, 0, maxn) {
pa[i] = i;
d[i] = 0;
}
}

int findSet(int x) {
if(pa[x] == x) return x;
else {
int root = findSet(pa[x]);
d[x] += d[pa[x]];
return pa[x] = root;
}
}

int main() {
freopen("input.txt", "r", stdin);
int kase;
scanf("%d", &kase);

while (kase--) {
initSet();
int n, u, v;
char cmd[9];
scanf("%d", &n);

while (scanf("%s", cmd) && cmd[0] != 'O') {
if(cmd[0] == 'E') {
scanf("%d", &u);
findSet(u);
cout << d[u] << endl;
} else if(cmd[0] == 'I') {
scanf("%d%d", &u, &v);
pa[u] = v;
d[u] = abs(u - v) % 1000;
}
}
}
}

并查集按秩压缩处理传递性问题(xor)

HDU3234
HDU3234

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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//
// main.cpp
// HDU3234
//
// Created by zhangmin chen on 2019/7/10.
// Copyright © 2019 zhangmin chen. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
#include <cmath>

using namespace std;
typedef long long llong;
typedef set<int>::iterator ssii;

const int maxn = 20000 + 10;
const int maxl = 40000 + 10;

#define Cmp(a, b) memcmp(a, b, sizeof(b))
#define Cpy(a, b) memcpy(a, b, sizeof(b))
#define Set(a, v) memset(a, v, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define _forS(i, l, r) for(set<int>::iterator i = (l); i != (r); i++)
#define _rep(i, l, r) for(int i = (l); i <= (r); i++)
#define _for(i, l, r) for(int i = (l); i < (r); i++)
#define _forDown(i, l, r) for(int i = (l); i >= r; i--)
#define debug_(ch, i) printf(#ch"[%d]: %d\n", i, ch[i])
#define debug_m(mp, p) printf(#mp"[%d]: %d\n", p->first, p->second)
#define debugS(str) cout << "dbg: " << str << endl;
#define debugArr(arr, x, y) _for(i, 0, x) { _for(j, 0, y) printf("%c", arr[i][j]); printf("\n"); }
#define _forPlus(i, l, d, r) for(int i = (l); i + d < (r); i++)


int n, q;
int pa[maxn], d[maxn];
int vis[maxn];
int line[maxl][3];
int data[maxn];

void initSet() {
Set(line, 0);
Set(data, 0);
_for(i, 0, maxn) {
pa[i] = i;
d[i] = 0;
}
}

int findSet(int x) {
if(x == pa[x]) return x;
else {
int root = findSet(pa[x]);
d[x] ^= d[pa[x]];
return pa[x] = root;
}
}


bool combine(int p, int q, int v) {
int rootp = findSet(p);
int rootq = findSet(q);

if(rootp == rootq) return (d[p] ^ d[q]) == v;
//debug(nil);

// union rootp and rootq, d[p] ^ d[q] = v
// pa[rootp] = rootq

if(rootp == n) swap(rootp, rootq);
pa[rootp] = rootq;
d[rootp] = (d[p] ^ d[q] ^ v);
return true;
}

int query(const int *data, int k) {
int ans = 0;
Set(vis, 0);
_for(i, 0, k) {
// d[data[i]]

if(vis[i]) continue;
int cnt = 0, root = findSet(data[i]);
_for(j, i, k) {
if(!vis[j] && root == findSet(data[j])) {
vis[j] = 1;
cnt++;

ans ^= d[data[j]];
}
}
if(root != n && cnt % 2 == 1) return -1;
}
return ans;
}

int main() {
freopen("input.txt", "r", stdin);
int cnt = 0;
while (scanf("%d%d", &n, &q) && (n + q)) {
initSet();
printf("Case %d:\n", ++cnt);
//debug(n);

int ic = 0;
bool bug = 0;
_for(i, 0, q) {
string str;
cin >> str;

if(str[0] == 'I') {
//
ic++;
int sz = 0;
while(cin >> line[i][sz++]) if(getchar() == '\n') break;
if(bug) continue;

int p = 0, q = 0, v = 0;
if(sz == 2) {
// I p v, data[0] = p, data[1] = v
p = line[i][0]; v = line[i][1];
q = n;
}
else if(sz == 3) {
// I p q v
p = line[i][0]; q = line[i][1]; v = line[i][2];
}

if(!combine(p, q, v)) {
printf("The first %d facts are conflicting.\n", ic);
bug = 1;
}
}
else if(str[0] == 'Q') {
// k p1 p2 ... pk
int k;
scanf("%d", &k);
// _for(i, 0, data.size()) cout << data[i] << " ";
// cout << endl;
_for(i, 0, k) scanf("%d", &data[i]);

if(bug) continue;
int res = query(data, k);
if(res == -1) printf("I don't know.\n");
else printf("%d\n", res);

}
// _for(i, 0, data.size()) cout << data[i] << " ";
// cout << endl;
}
puts("");
}
}

处理字符+数字混合输入的问题
方法一, getline(cin, line)吃掉前面cin/scanf的回车

1
2
3
4
5
6
7
8
9
10
输入I 5 10

string line;
getline(cin, line);

getline(cin, line);
stringstream ss(line);

int v;
while(ss >> v) vec.push_back(v);

方法二 while(cin >> ), getchar() == '\n’判断结束与否

1
2
3
int len = 0;
while(cin >> line[len++])
if(getchar() == '\n') break;

带删除操作的并查集

并查集带上删除操作比较麻烦
直接的处理方法, 给每个节点一个新的id
重新编号, x编号成id[x], 然后对id[]处理
同一个节点x,通过id的变化, 相当于原来集合中的节点删除,新开了一个id[x] = ++tot节点
原来集合中的点删除怎么体现? 其实是通过

1
root = find(x), sum[root] -= x, cnt[root]--

来完成的

1
2
3
4
5
6
7
8
9
10
11
del(int p)
// 先从原来的集合删除p元素
int root = find(id[p])
sum[root] -= p; cnt[root]--;

// p元素重新编号, 自成一个集合
id[p] = ++tot;
sum[id[p]] = p;
cnt[id[p]] = 1;
pa[id[p]] = id[p];

UVA11987

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
const int maxn = 100000 + 10;
int n, m;
int pa[maxn], cnt[maxn], id[maxn];
llong sum[maxn];
int tot;

void init(int n) {
_rep(i, 0, n) {
pa[i] = i;
id[i] = i;
sum[i] = i;
cnt[i] = 1;
}
tot = n;
}

int find(int x) {
return x == pa[x] ? x : (pa[x] = find(pa[x]));
}

void Union(int p, int q) {
int rootp = find(p);
int rootq = find(q);

pa[rootp] = rootq;
sum[rootq] += sum[rootp];
cnt[rootq] += cnt[rootp];
}

void change(int p) {
int pre = find(id[p]);
sum[pre] -= p;
cnt[pre]--;

id[p] = ++tot;
pa[id[p]] = id[p];
sum[id[p]] = (llong)p;
cnt[id[p]] = 1;
}


int main() {
freopen("input.txt", "r", stdin);
while (scanf("%d%d", &n, &m) != EOF) {
init(n);
_for(i, 0, m) {
//
int op;
scanf("%d", &op);

if(op == 1) {
//
int p, q;
scanf("%d%d", &p, &q);
if(find(id[p]) != find(id[q])) {
Union(id[p], id[q]);
}
}

if(op == 2) {
//
int p, q;
scanf("%d%d", &p, &q);
if(find(id[p]) == find(id[q])) continue;

change(p);
Union(id[p], id[q]);
}

if(op == 3) {
// print ans
int p;
scanf("%d", &p);
int root = find(id[p]);
printf("%d %lld\n", cnt[root], sum[root]);
}

}


}
}