据说这些并不对劲的内容是《信息学奥赛一本通提高篇》的配套练习。

并不会讲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树的更多相关文章

  1. 大规模字符串检索-压缩trie树

    本文使用压缩trie树实现字符串检索的功能.首先将字符串通过编码转化为二进制串,随后将二进制串插入到trie树中,在插入过程中同时实现压缩的功能. 字符编码采用Huffman,但最终测试发现不采用Hu ...

  2. 并不对劲的字符串专题(二):kmp

    据说这些并不对劲的内容是<信息学奥赛一本通提高篇>的配套练习. 先感叹一句<信息学奥赛一本通提高篇>上对kmp的解释和matrix67的博客相似度99%(还抄错了),莫非mat ...

  3. 835. 字符串统计(Trie树模板题)

    维护一个字符串集合,支持两种操作: “I x”向集合中插入一个字符串x: “Q x”询问一个字符串在集合中出现了多少次. 共有N个操作,输入的字符串总长度不超过 105105,字符串仅包含小写英文字母 ...

  4. Trie树|字典树(字符串排序)

    有时,我们会碰到对字符串的排序,若采用一些经典的排序算法,则时间复杂度一般为O(n*lgn),但若采用Trie树,则时间复杂度仅为O(n). Trie树又名字典树,从字面意思即可理解,这种树的结构像英 ...

  5. [转] Trie树详解及其应用

    一.知识简介         最近在看字符串算法了,其中字典树.AC自动机和后缀树的应用是最广泛的了,下面将会重点介绍下这几个算法的应用.       字典树(Trie)可以保存一些字符串->值 ...

  6. Trie树详解及其应用

    一.知识简介        最近在看字符串算法了,其中字典树.AC自动机和后缀树的应用是最广泛的了,下面将会重点介绍下这几个算法的应用.      字典树(Trie)可以保存一些字符串->值的对 ...

  7. 【动画】看动画轻松理解「Trie树」

    Trie树 Trie这个名字取自“retrieval”,检索,因为Trie可以只用一个前缀便可以在一部字典中找到想要的单词. 虽然发音与「Tree」一致,但为了将这种 字典树 与 普通二叉树 以示区别 ...

  8. Trie树(Prefix Tree)介绍

    本文用尽量简洁的语言介绍一种树形数据结构 -- Trie树. 一.什么是Trie树 Trie树,又叫字典树.前缀树(Prefix Tree).单词查找树 或 键树,是一种多叉树结构.如下图: 上图是一 ...

  9. 数据结构与算法—Trie树

    Trie,又经常叫前缀树,字典树等等.它有很多变种,如后缀树,Radix Tree/Trie,PATRICIA tree,以及bitwise版本的crit-bit tree.当然很多名字的意义其实有交 ...

随机推荐

  1. 【01背包变形】Robberies HDU 2955

    http://acm.hdu.edu.cn/showproblem.php?pid=2955 [题意] 有一个强盗要去几个银行偷盗,他既想多抢点钱,又想尽量不被抓到.已知各个银行 的金钱数和被抓的概率 ...

  2. Can you answer these queries(spoj 1043)

    题意:多次查询区间最长连续字段和 /* 用线段树维护区间最长子段和,最长左子段和,最长右子段和. */ #include<cstdio> #include<iostream> ...

  3. Nginx,Apache,Tomcat区别

    Nginx:一款能承受高并发的HTTP服务器,异步的,多个连接(万级别)可以对应一个进程,进行响应.基于事件驱动模型. Nginx优点:负载均衡.反向代理.处理静态文件优势. Apache:相对于Ng ...

  4. PatentTips - Reducing Write Amplification in a Flash Memory

    BACKGROUND OF THE INVENTION Conventional NAND Flash memories move data in the background to write ov ...

  5. 混合APP开发框架资料汇总

    Ionic(ionicframework)一款接近原生的Html5移动App开发框架 会html css js就可以开发app,Ionic基于angualrjs框架是一个专注于开发移动wap以及app ...

  6. HDU 3609 二分图多重匹配

    Escape Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Subm ...

  7. BZOJ 1798:

    6:       LAZY 线段树有乘法的更新    #include <cstdio> #include <cstring> #include <algorithm&g ...

  8. css三大特性

    层叠性: 当多个样式(样式的优先级相同)作用于同一个(同一类)标签时,样式发生了冲突,总是执行后边的代码(后边代码层叠前边的代码).和标签调用选择器的顺序没有关系. 继承性: 文字的大多属性都可以继承 ...

  9. Spring Cloud(8):Sleuth和Zipkin的使用

    场景: 某大型电商网站基于微服务架构,服务模块有几十个. 某天,测试人员报告该网站响应速度过慢.排除了网络问题之后,发现很难进一步去排除故障. 那么:如何对微服务的链路进行监控呢? Sleuth: 一 ...

  10. Ubuntu 16.04安装双显卡驱动方法收集

    说明:不一定有效,要不断尝试. http://www.linuxwang.com/html/2150.html http://blog.csdn.net/feishicheng/article/det ...