并不对劲的字符串专题(三):Trie树
据说这些并不对劲的内容是《信息学奥赛一本通提高篇》的配套练习。
并不会讲Trie树。
1.poj1056->
模板题。
2.bzoj1212->
设dp[i]表示T长度为i的前缀能否被理解。这样,对于所有满足T[(x+1)...i]是一个字典中的单词的x,dp[i]|=dp[x]。
所以,就可以将所有字典中的单词倒着建一棵Trie树,计算i时将T长度为i的前缀倒着在Trie树中匹配。
最后从后往前枚举i,第一个dp[i]=1的i就是答案。
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<stack>
#include<set>
#include<queue>
#define maxn 2000010
#define maxnd 3010
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
int f=0;char ch[20];
if(x==0){putchar('0'),putchar('\n');return;}
if(x<0){putchar('-'),x=-x;}
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
}
int ch[maxnd][26],cnt,go[maxnd],dp[maxn],n,m,ns,nt;
char t[maxnd],s[maxn];
int gx(char c){return c-'a';}
void ext()
{
int u=0;
for(int i=nt;i>=1;i--)
{
if(!ch[u][gx(t[i])])ch[u][gx(t[i])]=++cnt;
u=ch[u][gx(t[i])];
}
go[u]=1;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
{
scanf("%s",t+1);
nt=strlen(t+1);
ext();
}
//for(int i=0;i<=cnt;i++){for(int j=0;j<26;j++)if(ch[i][j])cout<<j<<":"<<ch[i][j]<<" ";cout<<endl;}
for(int i=1;i<=m;i++)
{
scanf("%s",s+1);
ns=strlen(s+1);dp[0]=1;
for(int j=1;j<=ns;j++)
{
int u=0;dp[j]=0;//cout<<gx(s[j])<<"*"<<endl;
for(int k=j;!dp[j]&&k>0&&ch[u][gx(s[k])];k--)
{
u=ch[u][gx(s[k])];
// cout<<go[u]<<endl;
if(go[u])dp[j]|=dp[k-1];
}
}
for(int j=ns;j>=0;j--)if(dp[j]){write(j);break;}
}
return 0;
}
3.bzoj1590->
听上去像裸题,但是很容易算晕。
先把所有密码前缀建成Trie树。
可以把FJ手里的每个串在所有密码前缀匹配的串分为两类:是它的前缀的串,它是这个串的前缀的串。
对于第一种,可以直接在Trie树中匹配,累加经过的点是几个串的结尾。
对于第二种,首先,如果在匹配过程中发现该走的边在Trie树中不存在,那么这一部分没有;如果匹配一直很顺利,最后走到了Trie树的一个节点x,那么答案就是子树x中一共有几个串的结尾。
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<stack>
#include<set>
#include<queue>
#define maxn 500010
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
int f=0;char ch[20];
if(x==0){putchar('0'),putchar('\n');return;}
if(x<0){putchar('-'),x=-x;}
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
}
int n,m,s[maxn],t[maxn],ch[maxn][2],val[maxn],w[maxn],ns,nt,cnt;
void ext()
{
int u=0;
for(int i=1;i<=nt;i++)
{
if(!ch[u][t[i]])ch[u][t[i]]=++cnt;
u=ch[u][t[i]];
}
val[u]++,w[u]++;
}
void dfs(int u)
{
for(int i=0;i<=1;i++)
if(ch[u][i])dfs(ch[u][i]),val[u]+=val[ch[u][i]];
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
{
nt=read();
for(int j=1;j<=nt;j++)t[j]=read();
ext();
}
dfs(0);
for(int i=1;i<=m;i++)
{
ns=read();
int u=0,f=0,cnt=0;
for(int j=1;j<=ns;j++)
{
s[j]=read();if(f)continue;
cnt+=w[u];
if(!ch[u][s[j]]){f=1;}
else u=ch[u][s[j]];
}
if(f)write(cnt);
else write(val[u]+cnt);
}
return 0;
}
4.bzoj4567->
这题听上去很复杂,但是会发现第一种完成方式肯定花费最高,而且存在一种方案能使得不会有第一种方式,那么肯定是不会有第一种方式的了。
根据第二种完成方式会发现对于某个单词,它对答案的贡献是$(它的序号)\times(1-以它为序号最大的后缀的单词数)$,所以,以它为序号最大的后缀的单词越多,这个单词就越该往后放,而且要放在以它为的后缀的单词的前面。
那么就可以将所有单词倒着建Trie树,并且进行路径压缩,使只剩下结束节点。最后的序列就是先走儿子数更少的儿子的dfs序。
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<stack>
#include<set>
#include<queue>
#define maxn 510010
#define LL long long
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
void write(LL x)
{
int f=0;char ch[20];
if(x==0){putchar('0'),putchar('\n');return;}
if(x<0){putchar('-'),x=-x;}
while(x)ch[++f]=x%10ll+'0',x/=10ll;
while(f)putchar(ch[f--]);
putchar('\n');
}
int siz[maxn],ch[maxn][26],fa[maxn],cnt,tim,dfn[maxn],ns,n;
LL ans;
char s[maxn];
vector<pair<int ,int> >son[maxn];
int gx(char c){return c-'a';}
void ext()
{
int u=0;
for(int i=ns;i>=1;i--)
{
if(!ch[u][gx(s[i])])ch[u][gx(s[i])]=++cnt;
u=ch[u][gx(s[i])];
}
siz[u]++;
}
void getf(int u,int f)
{
if(siz[u])fa[u]=f,f=u;
for(int i=0;i<26;i++)if(ch[u][i])getf(ch[u][i],f);
}
void dfs(int u,int f)
{
if(u)ans+=(++tim)-f,f=tim;
sort(son[u].begin(),son[u].end());
int lim=son[u].size();
for(int i=0;i<lim;i++)dfs(son[u][i].second,f);
}
int main()
{
n=read();
for(int i=1;i<=n;i++)scanf("%s",s+1),ns=strlen(s+1),ext();
getf(0,0);
for(int i=cnt;i>=1;i--)if(siz[i])siz[fa[i]]+=siz[i],son[fa[i]].push_back(make_pair(siz[i],i));
dfs(0,0);
write(ans);
return 0;
}
5.bzoj1954->
这道题实际上非常简单。因为给出的是一个树且不带修改,很容易可以想到树上的一条路径异或和可以由根两点的路径的异或和相互异或得到(根到lca的异或和会被抵消)。
那么将每个点的值转化为根到这个点路径的异或和,这道题便转化为给出n个数,找出两个数使其异或和最大。(很对劲的太刀流写的)
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<stack>
#include<set>
#include<queue>
#define maxn 100010
#define maxm (maxn<<1)
#define maxnd 3000010
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
int f=0;char ch[20];
if(x==0){putchar('0'),putchar('\n');return;}
if(x<0){putchar('-'),x=-x;}
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
}
int cnt,fir[maxn],nxt[maxm],v[maxm],w[maxm],ans;
int num[maxn],ch[maxnd][2],n,cntnd;
void ade(int u1,int v1,int w1){v[cnt]=v1,w[cnt]=w1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
void getn(int u,int fa)
{
for(int k=fir[u];k!=-1;k=nxt[k])
if(v[k]!=fa)num[v[k]]=num[u]^w[k],getn(v[k],u);
}
void ext(int x)
{
int u=0;
for(int i=30;i>=0;i--)
{
int tmp=x&(1<<i)?1:0;
if(!ch[u][tmp])ch[u][tmp]=++cntnd;
u=ch[u][tmp];
}
}
int getans(int x)
{
int u=0,ans=0;
for(int i=30;i>=0;i--)
{
int tmp=x&(1<<i)?1:0;
if(ch[u][tmp^1])u=ch[u][tmp^1],ans+=(tmp^1)*(1<<i);
else u=ch[u][tmp],ans+=(tmp)*(1<<i);
}
return ans;
}
int main()
{
memset(fir,-1,sizeof(fir));
n=read();
for(int i=1;i<n;i++){int x=read(),y=read(),z=read();ade(x,y,z),ade(y,x,z);}
getn(1,0);
for(int i=1;i<=n;i++)ext(num[i]);
for(int i=1;i<=n;i++)
{
int tmp=getans(num[i]);
ans=max(ans,num[i]^tmp);
}
write(ans);
return 0;
}
并不对劲的字符串专题(三):Trie树的更多相关文章
- 大规模字符串检索-压缩trie树
本文使用压缩trie树实现字符串检索的功能.首先将字符串通过编码转化为二进制串,随后将二进制串插入到trie树中,在插入过程中同时实现压缩的功能. 字符编码采用Huffman,但最终测试发现不采用Hu ...
- 并不对劲的字符串专题(二):kmp
据说这些并不对劲的内容是<信息学奥赛一本通提高篇>的配套练习. 先感叹一句<信息学奥赛一本通提高篇>上对kmp的解释和matrix67的博客相似度99%(还抄错了),莫非mat ...
- 835. 字符串统计(Trie树模板题)
维护一个字符串集合,支持两种操作: “I x”向集合中插入一个字符串x: “Q x”询问一个字符串在集合中出现了多少次. 共有N个操作,输入的字符串总长度不超过 105105,字符串仅包含小写英文字母 ...
- Trie树|字典树(字符串排序)
有时,我们会碰到对字符串的排序,若采用一些经典的排序算法,则时间复杂度一般为O(n*lgn),但若采用Trie树,则时间复杂度仅为O(n). Trie树又名字典树,从字面意思即可理解,这种树的结构像英 ...
- [转] Trie树详解及其应用
一.知识简介 最近在看字符串算法了,其中字典树.AC自动机和后缀树的应用是最广泛的了,下面将会重点介绍下这几个算法的应用. 字典树(Trie)可以保存一些字符串->值 ...
- Trie树详解及其应用
一.知识简介 最近在看字符串算法了,其中字典树.AC自动机和后缀树的应用是最广泛的了,下面将会重点介绍下这几个算法的应用. 字典树(Trie)可以保存一些字符串->值的对 ...
- 【动画】看动画轻松理解「Trie树」
Trie树 Trie这个名字取自“retrieval”,检索,因为Trie可以只用一个前缀便可以在一部字典中找到想要的单词. 虽然发音与「Tree」一致,但为了将这种 字典树 与 普通二叉树 以示区别 ...
- Trie树(Prefix Tree)介绍
本文用尽量简洁的语言介绍一种树形数据结构 -- Trie树. 一.什么是Trie树 Trie树,又叫字典树.前缀树(Prefix Tree).单词查找树 或 键树,是一种多叉树结构.如下图: 上图是一 ...
- 数据结构与算法—Trie树
Trie,又经常叫前缀树,字典树等等.它有很多变种,如后缀树,Radix Tree/Trie,PATRICIA tree,以及bitwise版本的crit-bit tree.当然很多名字的意义其实有交 ...
随机推荐
- python018 Python3 输入和输出
Python3 输入和输出在前面几个章节中,我们其实已经接触了 Python 的输入输出的功能.本章节我们将具体介绍 Python 的输入输出. 输出格式美化Python两种输出值的方式: 表达式语句 ...
- HDU 4641
动态更新后缀自动机,每次不断依据当前添加的节点不断往前寻找父节点上字符串最多可出现的次数 这里为了减少运算,当父节点已经达到k次就不在往前寻找,因为之前的必然达到k次,也已经统计在内 #include ...
- 【组合数模板】HDU 6114 Chess
http://acm.hdu.edu.cn/showproblem.php?pid=6114 [思路] 就是求C(m,n) [板] #include<iostream> #include& ...
- Help him--hdu5059(模拟 大坑)
http://acm.hdu.edu.cn/showproblem.php?pid=5059 直接说可能出现的情况 #include <iostream> #include <cst ...
- Copy List with Random Pointer (Hash表)
A linked list is given such that each node contains an additional random pointer which could point t ...
- [Bzoj1767][Ceoi2009]harbingers (树上斜率优化)
1767: [Ceoi2009]harbingers Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 451 Solved: 120[Submit][S ...
- [Bzoj1499][NOI2005]瑰丽华尔兹[简单DP]
1499: [NOI2005]瑰丽华尔兹 Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 1714 Solved: 1042[Submit][Status ...
- 某考试 T1 table
我们把每一行看成一个多项式 f[i][1] + f[i][2] * x + f[i][3] * x^2 + ..... + f[i][n] * x^(n-1) 的话,一行转移到下一行就相当于乘上一个{ ...
- System表空间大小有10Gb,使用率达到95%,
System表空间大小有10Gb,使用率达到95%,很好奇, 随后执行如下SQL,查看system表空间中使用空间最多的对象 SQL>SELECT * FROM DBA_SEGMENTS T W ...
- Node.js+Web TWAIN,实现Web文档扫描和图像上传
目录(?)[+] 通过Dynamic Web TWAIN SDK和Node.js的组合,只需要几行代码就可以实现在浏览器中控制扫描仪,获取图像后上传到远程服务器. 原文:Document Imag ...