目录
1、Trie树
1.1 Trie字符串统计
对于题目表明只存储大写字母、小写字母或者数字。
存储单词
查找单词
#include<iostream>
using namespace std;
const int N=2e4+10;
int cnt[N],son[N][26],index;
void insert(string str)
{
int p=0;
for(int i=0;str[i];i++)
{
int u=str[i]-'0';
if(!son[p][u]) son[p][u]=++index;
p=son[p][u];
}
cnt[p]++;
}
int query(string 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 m;
scanf("%d",&m);
string str;
char c;
while(m--)
{
cin>>c>>str;
if(c=='I')
{
insert(str);
}
else printf("%d\n",query(str));
}
return 0;
}
1.2 最大异或对
1.2.1 题目
1.2.2 异或运算 不进位加法
相同0,相异为1。
1.2.3 暴力做法
1.2.4 优化
使用trie优化第二层循环。
当走到叶节点的时候,就找到了与异或数,想异或最大的值。
trie可以存放二进制,因此trie可以存放一切数据
1.2.5 实例
1.2.6 代码
#include<iostream>
using namespace std;
const int N=31*1e5+10;
int n;
int son[N][2],index;
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]=++index;
p=son[p][u];
}
}
int query(int x)
{
int p=0,res=0;
for(int i=30;i>=0;i--)
{
int u=x>>i&1;
if(son[p][!u])
{
p=son[p][!u];
res=2*res+!u;
}
else
{
p=son[p][u];
res=2*res+u;
}
}
return res;
}
int main()
{
scanf("%d",&n);
int res=0,data;
while(n--)
{
scanf("%d",&data);
insert(data);
res=max(res,query(data)^data);
}
printf("%d",res);
return 0;
}
2.并查集
2.1什么是并查集
2.2 优化:路径压缩
o(1)的时间复杂度
2.3 合并集合
#include<iostream>
using namespace std;
const int N=1e5+10;
int p[N];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) p[i]=i;
while(m--)
{
char str[2];
int a,b;
scanf("%s%d%d",str,&a,&b);
if(*str=='M') p[find(a)]=find(b);
else
{
if(find(a)==find(b)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
2.4 连通块中点的数量
#include<iostream>
using namespace std;
const int N=1e5+10;
int p[N],cnt[N];
int n;
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
int m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) p[i]=i,cnt[i]=1;
string str;
while(m--)
{
char str[5];
int a,b;
scanf("%s",str);
if(*str=='C')
{
scanf("%d%d",&a,&b);
if(find(a)!=find(b))
{
cnt[find(b)]+=cnt[find(a)];
p[find(a)]=find(b);
}
}
else if(str[1]=='1')
{
scanf("%d%d",&a,&b);
if(find(a)==find(b)) printf("Yes\n");
else printf("No\n");
}
else if(str[1]=='2') scanf("%d",&a),printf("%d\n",cnt[find(a)]);
}
return 0;
}
2.5 食物链
2.5.1 题目分析
2.5.2 代码编写
并查集写法
错误
正确
维护操作
#include <iostream>
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()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) p[i] = i;
int res = 0;
while (m -- )
{
int t, x, y;
scanf("%d%d%d", &t, &x, &y);
if (x > n || y > n) res ++ ;
else
{
int px = find(x), py = find(y);
if (t == 1)
{
if (px == py && (d[x] - d[y]) % 3) res ++ ;
else if (px != py)
{
p[px] = py;
d[px] = d[y] - d[x];
}
}
else
{
if (px == py && (d[x] - d[y] - 1) % 3) res ++ ;
else if (px != py)
{
p[px] = py;
d[px] = d[y] + 1 - d[x];
}
}
}
}
printf("%d\n", res);
return 0;
}
3、堆
3.1 堆的基本操作
3.2什么是堆
堆是一颗完全二叉树
3.3 堆的存储
堆是stl中的优先队列
3.4 down和up操作
down操作模拟(红色)
up操作模拟(绿色)
使用down和up实现堆的操作
插入 删除 up down 时间复杂度o(logn)
3.5 堆排序
题目需要的操作
快速建堆
n/2处开始,下边的全是叶子节点,满足堆的条件,因为叶子节点下方无孩子。他就是最小的。(小根堆)
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n, m;
int h[N], cnt;
void down(int u)
{
int t = u;
if (u * 2 <= cnt && h[u * 2] < h[t]) t = u * 2;
if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
if (u != t)
{
swap(h[u], h[t]);
down(t);
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &h[i]);
cnt = n;
for (int i = n / 2; i; i -- ) down(i);
while (m -- )
{
printf("%d ", h[1]);
h[1] = h[cnt -- ];
down(1);
}
puts("");
return 0;
}
3.6 模拟堆
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
const int N = 100010;
int h[N], ph[N], hp[N], cnt;
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 <= cnt && h[u * 2] < h[t]) t = u * 2;
if (u * 2 + 1 <= cnt && 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] < h[u / 2])
{
heap_swap(u, u / 2);
u >>= 1;
}
}
int main()
{
int n, m = 0;
scanf("%d", &n);
while (n -- )
{
char op[5];
int k, x;
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;
up(k);
down(k);
}
}
return 0;
}