1.KMP算法模板
#include <bits/stdc++.h>
using namespace std;
const int N=100010,M=1000010;
char p[N],s[M];
int ne[N];
int main()
{
int m,n;
cin>>n>>p+1>>m>>s+1;
for(int i=2,j=0;i<=n;i++)
{
while(j&&p[i]!=p[j+1]) j=ne[j];
if(p[i]==p[j+1]) j++;
ne[i]=j;
}
for(int i=1,j=0;i<=m;i++)
{
while(j&&s[i]!=p[j+1]) j=ne[j];
if(s[i]==p[j+1]) j++;
if(j==n)
{
printf("%d ",i-j);
j=ne[j];
}
}
return 0;
}
2.Trie树:高效地存储和查找字符串集合的数据结构
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int idx,son[N][26],cnt[N];
char str[N];
void insertt(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];//p指向刚创建出来的新指针
}
cnt[p]++;//以p结尾的单词数+1
}
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];
scanf("%s%s",op,str);
if(op[0]=='I') insertt(str);
else printf("%d\n",query(str));
}
return 0;
}
最大异或对
#include <bits/stdc++.h>
using namespace std;
const int N=100010,M=31*N;
int a[N];
int idx,son[M][2];
void inserrt(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,res=0;
for(int i=30;i>=0;i--)
{
int u=x>>i&1;
if(son[p][!u])
{
p=son[p][!u];
res=res*2+!u;
}
else
{
p=son[p][u];
res=res*2+u;
}
}
return res;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int res=0;
for(int i=0;i<n;i++)
{
inserrt(a[i]);
int t=query(a[i]);
res=max(res,a[i]^t);
}
printf("%d\n",res);
return 0;
}
3.并查集:将两个集合合并或者询问两个数是否在一个集合中
基本原理:每个集合用一棵树表示,树根的编号就是集合的编号,每个节点存储他的父节点,p[x]表示x 的父节点
如何判断根节点:p[x]=x;
如何求x的集合编号:while(x!=p[x]) x=p[x];
如何合并两个集合:p[x]是x集合编号,p[y]是y集合编号,p[x]=y;
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int p[N];
int findd(int x)//返回x的祖宗节点+路径压缩
{
if(p[x]!=x) p[x]=findd(p[x]);
return p[x];
}
int main()
{
int n,m,a,b;
char op[2];
cin>>n>>m;
for(int i=1;i<=n;i++) p[i]=i;
while(m--)
{
scanf("%s%d%d",&op,&a,&b);
if(op[0]=='M')
{
p[findd(a)]=findd(b);
}
else
{
if(findd(a)==findd(b)) puts("Yes");
else puts("No");
}
}
return 0;
}
连通块中点的数量
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int p[N],sizee[N];
int findd(int x)//返回x的祖宗节点+路径压缩
{
if(p[x]!=x) p[x]=findd(p[x]);
return p[x];
}
int main()
{
int n,m,a,b;
char op[2];
cin>>n>>m;
for(int i=1;i<=n;i++) {p[i]=i;sizee[i]=1;}
while(m--)
{
scanf("%s",op);
if(op[0]=='C')
{
scanf("%d%d",&a,&b);
if(findd(a)==findd(b)) continue;
sizee[findd(b)]+=sizee[findd(a)];
p[findd(a)]=findd(b);
}
else if(op[1]=='1')
{
scanf("%d%d",&a,&b);
if(findd(a)==findd(b)) puts("Yes");
else puts("No");
}
else
{
scanf("%d",&a);
printf("%d\n",sizee[findd(a)]);
}
}
return 0;
}
食物链——>妙啊
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int d[N],p[N];
int findd(int x)//找根节点
{
if(p[x]!=x)//如果x不是根节点
{
int t=findd(p[x]);//t位p[x]的根节点
d[x]+=d[p[x]];//x到根节点的距离
p[x]=t;//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;
int res=0;
while(m--)
{
int x,y,t;
scanf("%d%d%d",&t,&x,&y);
if(x>n||y>n) res++;
else
{
int px=findd(x),py=findd(y);
if(t==1)
{
if(px==py&&(d[x]-d[y])%3!=0) res++;//xy在一个集合并且不是一类-》模3的余数不相同
else if(px!=py)//不在同一个集合上
{
p[px]=py;
d[px]=d[y]-d[x];
}
}
else
{
if(px==py&&(d[x]-d[y]-1)%3!=0) res++;
else if (px!=py)
{
p[px]=py;
d[px]=d[y]+1-d[x];
}
}
}
}
printf("%d\n",res);
return 0;
}