《算法基础》Trie树,并查集,堆
一. Trie树
Tire树 用来高效存储和查询字符串的
源代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100010;
int son[N][26], cnt[N], idx; //son[p][n] 表示 p树下面的[n+'a'] 存在 cnt[i] 已i结尾的字符串存在。 idx多少个结点
char str[N];
void add(char *str)
{
int p = 0; //p表示 有多少个结点
for (int i = 0; str[i]; i ++) {
int u = str[i] - '0';
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] - '0';
if (!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
int main()
{
int n;
cin >> n;
char op[3];
while (n --) {
scanf("%s%s", op, str); //这里不要带&
if (*op == 'I') { //记住 op[0]
add(str);
} else {
printf("%d\n", query(str));
}
}
return 0;
}
二. 并查集及并查集习题
源代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int p[N];
int n, m;
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]); //回溯的时候起到了优化的作用 让x直接指向父节点
return p[x];
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++) p[i] = i;
int a, b;
char op[2];
while (m --) {
cin >> op >> a >> b;
if (*op == 'M') {
p[find(a)] = find(b); //把a链接到b后面 也就是a b之间连一条边
} else {
if (find(a) == find(b)) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
}
}
return 0;
}
习题: 食物链
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 50010;
int n, m;
int p[N], d[N];
int find(int x)
{
if (p[x] != x) {
int t = find(p[x]);
d[x] += d[p[x]];
p[x] = t;
}
return p[x];
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++) p[i] = i;
int op, x, y, res = 0;
while (m --) {
scanf("%d%d%d", &op, &x, &y);
if (x > n || y > n) res ++;
else {
int px = find(x), py = find(y);
if (op == 1) { //同类
if (px == py && (d[x] - d[y]) % 3) res ++;
else if(px != py) {
p[px] = py;
d[px] = d[y] - d[x];
//if ((d[x] - d[y]) % 3) res ++; //第一次能连到树上的都是真的 验证后面的句子
}
} else { //x 吃 y
if (px == py && (d[x]- 1 - d[y]) % 3) res ++;
else if(px != py) {
p[px] = py;
d[px] = d[y] - d[x] + 1;
//if ((d[x] - 1 - d[y]) % 3) res ++;
}
}
}
}
cout << res << endl;
return 0;
}
三. 堆
源代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100010;
int n, m; //m为数组下标
int h[N], hp[N], ph[N], cnt; //cnt为heap下标
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 x)
{
int t = x;
if (2 * x <= cnt && h[2 * x] < h[t]) t = 2 * x;
if (2 * x + 1 <= cnt && h[2 * x + 1] < h[t]) t = 2 * x + 1;
if (t != x) {
heap_swap(t, x);
down(t);
}
}
void up(int x)
{
while (x / 2 && h[x / 2] > h[x]) {
heap_swap(x / 2, x);
x = x / 2;
}
}
int main()
{
cin >> n;
char op[5];
int k = 0, x = 0;
while (n --) {
scanf("%s", op);
if (!strcmp(op, "I")) {
scanf("%d", &x);
cnt ++;
m ++;
ph[m] = cnt;
hp[cnt] = m;
h[cnt] = x;
up(cnt);
}
else if (!strcmp(op, "PM")) {
printf("%d\n", h[1]);
}
else if (!strcmp(op, "DM")) {
heap_swap(1, cnt);
cnt --;
down(1);
}
else if (!strcmp(op, "D")) { //在堆中,在最后删除一个值
scanf("%d", &k);
k = ph[k];
heap_swap(k, cnt);
cnt --;
up(k);
down(k);
}
else {
scanf("%d%d", &k, &x);
k = ph[k];
h[k] = x;
down(k);
up(k);
}
}
return 0;
}