Acwing-----算法基础课之第二讲(数据结构二)
835 Trie字符串统计
#include <iostream>
using namespace std;
const int N = 100010;
int n;
int son[N][26], cnt[N], idx; //下标是0的点既是根节点又是空结点
char str[N];
void insert(char str[]) {
int p = 0;
for (int i = 0; str[i]; ++i) {
int u = str[i] - 'a';
if (!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
cnt[p]++;
}
int query(char str[]) {
int p = 0;
for (int i = 0; str[i]; ++i) {
int u = str[i] - 'a';
if (!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
int main() {
int n;
cin >> n;
while (n--) {
char op[2];
cin >> op >> str;
if (op[0] == 'I') insert(str);
else cout << query(str) << endl;
}
return 0;
}
143.最大异或对
#include <iostream>
using namespace std;
const int N = 100010, M = 31 * N;
int n;
int a[N], son[M][2], idx;
void insert(int x) {
int p = 0;
for (int i = 30; i >= 0; --i) {
int u = x >> i & 1;
if (!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
}
int query(int x) {
int p = 0, ans = 0;
for (int i = 30; i >= 0; --i) {
int u = x >> i & 1;
if (son[p][!u]) {
ans = ans * 2 + !u;
p = son[p][!u];
} else {
p = son[p][u];
ans = ans * 2 + u;
}
}
return ans;
}
int main() {
cin >> n;
for (int i = 0; i < n; ++i) cin >> a[i];
int ans = 0;
for (int i = 0; i < n; ++i) {
insert(a[i]);
int t = query(a[i]);
ans = max(ans, a[i] ^ t);
}
cout << ans << endl;
return 0;
}
836.合并集合
并查集: 1.将两个集合合并;
2.询问两个元素是否在一个集合中。
基本原理:每个集合用一棵树来表示,树根的编号就是整个集合的编号,每个节点存储它的父节点,p[x]表示它的父节点。
#include <iostream>
using namespace std;
const int N = 100010;
int n, m, p[N];
// 返回x的祖宗节点(路径压缩)
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) p[i] = i;
while (m--) {
char op[2];
int a, b;
cin >> op >> a >> b;
if (op[0] == 'M') p[find(a)] = find(b);
else {
if (find(a) == find(b)) puts("Yes");
else puts("No");
}
}
return 0;
}
837.连通块中点的数量
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int p[N], sz[N];
int find(int x) {
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) p[i] = i, sz[i] = 1;
while (m--) {
char op[5];
int a, b;
cin >> op;
if (op[0] == 'C') {
cin >> a >> b;
if (find(a) == find(b)) continue;
sz[find(b)] += sz[find(a)];
p[find(a)] = find(b);
}
else if (op[1] == '1') {
cin >> a >> b;
if (find(a) == find(b)) puts("Yes");
else puts("No");
} else {
cin >> a;
cout << sz[find(a)] << endl;
}
}
return 0;
}
838.堆排序
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n, m, h[N], sz;
void down(int u) {
int t = u;
if (u * 2 <= sz && h[u * 2] < h[t]) t = u * 2;
if (u * 2 + 1 <= sz && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
if (u != t) {
swap(h[u], h[t]);
down(t);
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> h[i];
sz = n;
for (int i = n / 2; i; --i) down(i);
while (m--) {
cout << h[1] << " ";
h[1] = h[sz--];
down(1);
}
return 0;
}
839.模拟堆
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
const int N = 100010;
int n, m, ph[N], hp[N], h[N], sz;
void heap_swap(int a, int b) {
swap(ph[hp[a]], ph[hp[b]]);
swap(hp[a], hp[b]);
swap(h[a], h[b]);
}
void down(int u) {
int t = u;
if (u * 2 <= sz && h[u * 2] < h[t]) t = u * 2;
if (u * 2 + 1 <= sz && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
if (u != t) {
heap_swap(u, t);
down(t);
}
}
void up(int u) {
while (u / 2 && h[u / 2] > h[u]) {
heap_swap(u / 2, u);
u /= 2;
}
}
int main() {
cin >> n;
while (n --) {
char op[10];
int k, x;
cin >> op;
if (!strcmp(op, "I")) {
cin >> x;
sz++;
m++;
ph[m] = sz, hp[sz] = m;
h[sz] = x;
up(sz);
} else if (!strcmp(op, "PM")) cout << h[1] << endl;
else if (!strcmp(op, "DM")) {
heap_swap(1, sz--);
down(1);
} else if (!strcmp(op, "D")) {
cin >> k;
k = ph[k];
heap_swap(k, sz);
sz--;
down(k), up(k);
} else {
cin >> k >> x;
k = ph[k];
h[k] = x;
down(k), up(k);
}
}
return 0;
}
840.模拟散列表
哈希表:
1.存储结构:开放寻址法、拉链法
2.字符串哈希方式
//拉链法
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100003;
int h[N];
int e[N], ne[N], idx;
void insert(int x) {
int k = (x % N + N) % N;
e[idx] = x, ne[idx] = h[k], h[k] = idx++;
}
bool find(int x) {
int k = (x % N + N) % N;
for (int i = h[k]; i != -1; i = ne[i]) {
if (e[i] == x) return true;
}
return false;
}
int main() {
int n;
cin >> n;
memset(h, -1, sizeof h);
while (n--) {
char op[2];
int x;
scanf("%s%d", op, &x);
if (*op == 'I') insert(x);
else {
if (find(x)) puts("Yes");
else puts("No");
}
}
return 0;
}
// 开放寻址法
#include <iostream>
#include <cstring>
using namespace std;
const int N = 200003, null = 0x3f3f3f3f;
int h[N];
int find(int x) {
int k = (x % N + N) % N;
while (h[k] != null && h[k] != x) {
++k;
if (k == N) k = 0;
}
return k;
}
int main() {
int n, x;
cin >> n;
memset(h, 0x3f, sizeof h);
while (n--) {
char op[2];
scanf("%s%d", op, &x);
int k = find(x);
if (*op == 'I') h[k] = x;
else {
if (h[k] != null) puts("Yes");
else puts("No");
}
}
return 0;
}
841.字符串哈希
#include <iostream>
using namespace std;
const int N = 100010, P = 131;
typedef unsigned long long ULL;
char str[N];
ULL h[N], p[N];
ULL get(int l, int r) {
return h[r] - h[l - 1] * p[r - l + 1];
}
int main() {
int n, m;
scanf("%d%d%s", &n, &m, str + 1);
p[0] = 1;
for (int i = 1; i <= n; ++ i) {
p[i] = p[i - 1] * P;
h[i] = h[i - 1] * P + str[i];
}
while (m--) {
int l1, l2, r1, r2;
cin >> l1 >> r1 >> l2 >> r2;
if (get(l1, r1) == get(l2, r2)) puts("Yes");
else puts("No");
}
return 0;
}