我不知道为什么在进阶指南上Trie树是一个基本数据结构。。
模板
定义
a[x].link[ch]表示节点x的第ch个字母的节点编号
temp表示节点编号
long long temp=1;
struct atree
{
long long link[26];
bool endflag;
}
a[600010];
插入
依次扫描字符串s中的每个字符ch
若ch为空,则新建一个节点temp
void build(long long i,long long x)
//x表示当前节点编号,i枚举字符串的每一位
{
if (i==s.size())
{
a[x].endflag=true;//标记当前节点为尾节点
return;
}
long long ch=s[i]-'a';//ch表示当前字符(转换为数字)
if (a[x].link[ch]==0) a[x].link[ch]=++temp;
build(i+1,a[x].link[ch]);
}
检索
同样地,依次扫描字符串s中的每个字符ch
若ch为空,则说明字符串s没有被插入过Trie树,结束检索
bool find(long long i,long long x)
{
if (i==s.size())
{
if (a[x].endflag) return true;
else return false;
}//返回x是否为尾节点
long long ch=s[i]-'a';//ch为当前节点的第i位字母的节点编号
if (a[x].link[ch]==0) return false;
find(i+1,a[x].link[ch]);
}
T1trie树模板
它要求单词列表对应的单词查找树的节点数
这题只要建一棵trie树就好了,输出temp
#include<bits/stdc++.h>
using namespace std;
string s;
long long temp=1;
struct atree
{
long long link[26];
}
a[600010];
void build(long long i,long long x)
{
if (i==s.size()) return;
long long ch=s[i]-'A';
if (a[x].link[ch]==0) a[x].link[ch]=++temp;
build(i+1,a[x].link[ch]);
}
int main()
{
while(getline(cin,s))
build(0,1);
printf("%lld\n",temp);
return 0;
}
T2 L语言
它要求这段文章在字典D可以被理解的最长前缀的位置
同样地,先建一棵trie树,只不过检索的时候要新开一个b数组,用来存储从字符串的当前字符开始扫描能够达到的最长前缀的长度,比如b[14]=6则表示从s的第6位开始扫,最长的前缀长度为14
它的标签是DP,我不是很能理解。。
#include<bits/stdc++.h>
using namespace std;
long long n,m,temp=1,b[1000010],ans;
string s;
struct atree
{
long long link[26];
bool endflag;
}
a[600010];
inline int read()
{
int num=0,flag=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar())
if (c=='-') flag=-1;
for (;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
return num*flag;
}
void build(long long i,long long x)
{
if (i==s.size())
{
a[x].endflag=true;
return;
}
long long ch=s[i]-'a';
if (a[x].link[ch]==0) a[x].link[ch]=++temp;
build(i+1,a[x].link[ch]);
}
void find(long long i,long long x)
{
if (a[x].endflag)
{
b[i]=b[0];
ans=max(ans,i);
}
if (i==s.size()) return;
long long ch=s[i]-'a';
if (a[x].link[ch]==0) return;
find(i+1,a[x].link[ch]);
}
int main()
{
n=read();
m=read();
for (int i=1;i<=n;++i)
{
getline(cin,s);
build(0,1);
}
for (int i=1;i<=m;++i)
{
getline(cin,s);
ans=0;
b[0]=i;
for (int j=0;j<=s.size();++j)
if (b[j]==i) find(j,1);
printf("%lld\n",ans);
}
return 0;
}
T3 First
它要求哪些字符串可以以某种顺序排在所有字符串中首位
这类题目现在都要转换一下了啊
所以我们现在把题目意思理解为——对于每一个字符串,要满足两个条件:
①没有字符串前缀;②在同一个父亲下,该儿子要比其他兄弟的优先度高。
这里就要两步——①检索:如果在检索过程中遇见了其他字符串的尾节点,就说明它有前缀,不可以;②拓扑排序:如果出现了环或者冲突什么的,将会导致拓扑完了之后有些点的入度不为0,不可以。
#include<bits/stdc++.h>
using namespace std;
long long k,temp=1,id[50],ans[30010],tot;
string s[30010];
bool flag,b[50][50];
struct atree
{
long long link[26];
bool endflag;
}
a[600010];
inline int read()
{
int num=0,flag=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar())
if (c=='-') flag=-1;
for (;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
return num*flag;
}
void build(long long i,long long x,int t)
{
if (i==s[t].size())
{
a[x].endflag=true;
return;
}
long long ch=s[t][i]-'a';
if (a[x].link[ch]==0) a[x].link[ch]=++temp;
build(i+1,a[x].link[ch],t);
}
void find(int i,int x,int t)
{
if (i==s[t].size()) return;
if (a[x].endflag)
{
flag=false;
return;
}
long long ch=s[t][i]-'a';
for (int j=0;j<26;++j)
if (a[x].link[j]&&ch!=j&&b[ch][j]==false)
{
b[ch][j]=true;
id[j]++;
}
find(i+1,a[x].link[ch],t);
}
void topsort()
{
long long head=0,tail=0,q[50]={};
for (int i=0;i<26;++i)
if (id[i]==0) q[++tail]=i;
while (head<tail)
{
long long k=q[++head];
for (int i=0;i<26;++i)
if (b[k][i])
{
id[i]--;
if (id[i]==0) q[++tail]=i;
}
}
for (int i=0;i<26;++i)
if (id[i])
{
flag=false;
return;
}
}
int main()
{
k=read();
for (int i=1;i<=k;++i)
{
getline(cin,s[i]);
build(0,1,i);
}
for (int i=1;i<=k;++i)
{
flag=true;
temp=0;
memset(b,0,sizeof(b));
memset(id,0,sizeof(id));
find(0,1,i);
topsort();
if (flag) ans[++tot]=i;
}
printf("%lld\n",tot);
for (int i=1;i<=tot;++i)
cout<<s[ans[i]]<<endl;
return 0;
}
T4秘密消息
它要求有多少信息和这条密码有着相同的前缀
这里的a[x].s1表示x点被几个字符串覆盖,a[x].s2表示x点为几个字符串的尾节点,所以如果当前点不是尾节点,ans加上s2,如果是,加上s1
自己理解一下啦
#include<bits/stdc++.h>
using namespace std;
long long m,n,k,b[10010],temp=1,ans;
struct atree
{
long long link[5],s1,s2;
bool endflag;
}
a[600010];
inline int read()
{
int num=0,flag=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar())
if (c=='-') flag=-1;
for (;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
return num*flag;
}
void build(long long i,long long x)
{
if (i>k)
{
a[x].endflag=true;
a[x].s1++;
a[x].s2++;
return;
}
long long ch=b[i];
if (a[x].link[ch]==0) a[x].link[ch]=++temp;
a[x].s1++;
build(i+1,a[x].link[ch]);
}
void find(long long i,long long x)
{
if (i>k)
{
ans+=a[x].s1;
return;
}
long long ch=b[i];
ans+=a[x].s2;
if (a[x].link[ch]==0) return;
find(i+1,a[x].link[ch]);
}
int main()
{
m=read();
n=read();
for (int i=1;i<=m;++i)
{
k=read();
for (int j=1;j<=k;++j)
b[j]=read();
build(1,1);
}
for (int i=1;i<=n;++i)
{
k=read();
for (int j=1;j<=k;++j)
b[j]=read();
ans=0;
find(1,1);
printf("%lld\n",ans);
}
return 0;
}
T5背单词
坑。
#include<bits/stdc++.h>
using namespace std;
long long n,l,temp,linkk[1020010],tot,k,sum,tail,dfs[1020010],ans;
bool f[1020010];
string s;
struct atree
{
long long link[26],endflag;
}
a[1020010];
struct etree
{
long long y,v,next,father;
}
e[1020010];
struct btree
{
long long id,val;
}
b[600010];
bool mycmp(btree aa,btree bb)
{
return aa.val<bb.val;
}
inline int read()
{
int num=0,flag=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar())
if (c=='-') flag=-1;
for (;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
return num*flag;
}
void insertt(long long ss,long long ee)
{
e[++tot].y=ee;
e[tot].next=linkk[ss];
linkk[ss]=tot;
}
void build(long long i,long long x,long long t)
{
if (i<0)
{
a[x].endflag=t;
return;
}
long long ch=s[i]-'a';
if (a[x].link[ch]==0) a[x].link[ch]=++temp;
build(i-1,a[x].link[ch],t);
}
void find(long long x,long long t)
{
if (a[x].endflag)
{
insertt(t,a[x].endflag);
insertt(a[x].endflag,t);
t=a[x].endflag;
}
for (int i=0;i<26;++i)
if (a[x].link[i]) find(a[x].link[i],t);
}
void dfs1(long long t)
{
e[t].v=1;
for (int i=linkk[t];i;i=e[i].next)
{
long long k=e[i].y;
if (k==e[t].father) continue;
e[k].father=t;
dfs1(k);
e[t].v+=e[k].v;
}
}
void dfs2(long long t)
{
f[t]=true;
long long head=tail;
sum++;
dfs[t]=sum;
for(int i=linkk[t];i;i=e[i].next)
{
k=e[i].y;
if (k==e[t].father) continue;
b[++tail].id=k;
b[tail].val=e[k].v;
}
if (head==tail) return;
sort(b+head+1,b+tail+1,mycmp);
for (int i=head+1;i<=tail;++i)
{
if (f[b[i].id]) continue;
dfs2(b[i].id);
ans+=dfs[b[i].id]-dfs[t];
}
}
int main()
{
n=read();
for (int i=1;i<=n;++i)
{
getline(cin,s);
l=s.size();
build(l-1,0,i);
}
find(0,0);
dfs1(0);
dfs2(0);
printf("%lld\n",ans);
return 0;
}