Tire
高效存储和查找字符串
这里就是一个树,然后把每个结尾字母做个标记
#include<iostream>
using namespace std;
const int N=100010;
int e[N][26],cnt[N],idx;
void insert(string a){
int p=0;
for(int i=0;i<a.size();i++){
if(!e[p][a[i]-'a'])e[p][a[i]-'a']=++idx;
p=e[p][a[i]-'a'];
}
cnt[p]++;
}
int look(string a){
int p=0;
for(int i=0;i<a.size();i++){
if(!e[p][a[i]-'a'])return 0;
p=e[p][a[i]-'a'];
}
return cnt[p];
}
int main(){
cin.tie(0);
int n=0;
string a;
cin>>n;
char b;
while(n--){
cin>>b>>a;
if(b=='I')insert(a);
else{
int x=look(a);
cout<<x<<endl;
}
}
}
并查集
1.将两个集合合并;
2.询问两个元素是否在一个集合当中
基本原理:每个集合用一棵树来表示,树根的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点
问题1:如何判断数根 if(p[x]==x)
问题2:如何求x的集合编号white(p[x]!=x)x=p[x]
问题3:如何合并两个集合px是x的集合编号,py是y的集合编号p[x]=y;
优化:路径压缩
#include<iostream>
using namespace std;
int n,m;
const int N=100010;
int e[N];
int find(int a){
if(e[a]!=a)e[a]=find(e[a]);
return e[a];
}
int main(){
cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)e[i]=i;
while(m--){
char op;
int a,b;
cin>>op>>a>>b;
if(op=='M')e[find(a)]=find(b);
else{
if(find(a)==find(b))cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
}
手写堆
1.插入一个数 heap[++size]=x;up(size);
2.求集合当中的最小值 heap[1];
3.删除最小值 heap[1]=heap[size];size–;down(1)
STL的堆以下两个无法直接实现
4.删除任意元素 heap[k]=heap[size];size–;down(k);up(k);
5.修改任意元素 heap[k]=x;down,up
堆是一个完全二叉树
小根堆:根是最小值,每个点都满足<=下面两边的点
存储:用一维数组
根是1;x的左儿子的2x,x的右儿子是2x+1;
堆的两个基本操作:down(x),up(x)
对应有大根堆
先实现一个简单版堆
#include <iostream>
#include <string>
using namespace std;
const int N=100010;
int siz,p[N];
void down(int u){
int t = u;
if (u * 2 <= siz && p[u * 2] < p[t]) t = u * 2;
if (u * 2 + 1 <= siz && p[u * 2 + 1] < p[t]) t = u * 2 + 1;
if (u != t)
{
swap(p[u], p[t]);
down(t);
}
}
void up(int a){
while(a/2&&p[a]<p[a/2]){
swap(p[a],p[a/2]);
u/=2;
}
}
int main(){
int m,n;
scanf("%d%d",&m,&n);
while(m--){
int a;
cin>>a;
siz++;
p[siz]=a;
}
for(int i=siz/2;i;i--){
down(i);
}
while(n--){
cout<<p[1]<<" ";
p[1]=p[siz];
siz--;
down(1);
}
}
复杂版堆,有新的ph和hp数组,用于存储第k个插入元素的下标i和第i个下标元素的插入顺序k。迪杰斯特拉算法会用到。
#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;
}