【BZOJ4231】回忆树 离线+fail树+KMP
【BZOJ4231】回忆树
Description
Input
Output
Sample Input
1 2 w
2 3 w
3 4 x
4 5 w
5 6 w
6 7 x
7 8 w
8 9 w
9 10 x
10 11 w
11 12 w
1 7
wwx
1 12
www
1 12
w
Sample Output
0
8
HINT
题解:一开始想反了,以为要把原树建成AC自动机。。。不可做?
我们将询问分成两段,一段上去的和一段下去的,这样只需要对询问串的正串和反串分别维护AC自动机即可。那么中间的呢?由于总长不超过2K,所以暴力拿出来跑KMP即可。
考虑每一段,我们采用离线的方法,将询问挂链到树的节点上,在上端的点系数为-1,下端的点系数为+1,然后DFS一遍整棵树,每扫到一个点就将这个点在AC自动机中对应点的权值+1。然后考虑在这个点挂链的所有询问,用询问串对应点在fail树中子树的点权和更新答案即可。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=100010;
int n,m,t1,t2,l1,l2,cnt;
queue<int> Q;
struct AC
{int tot;int ch[26],fail;
}a1[maxn*3],a2[maxn*3];
struct Fail_Tree
{int tot;AC *a;vector<int> ch[maxn*3];int p[maxn*3],q[maxn*3],s[maxn*3];void dfs(int x){p[x]=++p[0];for(int i=0;i<(int)ch[x].size();i++) dfs(ch[x][i]);q[x]=p[0];}void build(){Q.push(1);int i,u;while(!Q.empty()){u=Q.front(),Q.pop();for(i=0;i<26;i++){if(u==1){if(a[u].ch[i]) Q.push(a[u].ch[i]),a[a[u].ch[i]].fail=1;else a[u].ch[i]=1;continue;}if(!a[u].ch[i]){a[u].ch[i]=a[a[u].fail].ch[i];continue;}Q.push(a[u].ch[i]);a[a[u].ch[i]].fail=a[a[u].fail].ch[i];}}for(i=2;i<=tot;i++) ch[a[i].fail].push_back(i);dfs(1);}inline void updata(int x,int v){for(int i=x;i<=tot;i+=i&-i) s[i]+=v;}inline int query(int x){int i,ret=0;for(i=x;i;i-=i&-i) ret+=s[i];return ret;}
}f1,f2;
struct QUERY
{int a,b,u,v,top,ans;
}q[maxn];
struct node
{int org,k;node() {}node(int a,int b) {org=a,k=b;}
};
vector<node> b1[maxn],b2[maxn];
int val[maxn<<1],next[maxn<<1],to[maxn<<1],head[maxn],fa[20][maxn],Log[maxn],nxt[maxn*3],from[maxn],dep[maxn];
char T[maxn*3],S[maxn];
inline void add(int a,int b,int c)
{to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
void getfa(int x)
{for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[0][x])fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,from[to[i]]=val[i],getfa(to[i]);
}
inline int lca(int a,int b)
{if(dep[a]<dep[b]) swap(a,b);int i;for(i=Log[dep[a]-dep[b]];i>=0;i--) if(dep[fa[i][a]]>=dep[b]) a=fa[i][a];if(a==b) return a;for(i=Log[dep[a]];i>=0;i--) if(fa[i][a]!=fa[i][b]) a=fa[i][a],b=fa[i][b];return fa[0][a];
}
inline int FA(int x,int y)
{for(int i=Log[y];i>=0;i--) if((1<<i)<=y) y-=(1<<i),x=fa[i][x];return x;
}
inline int KMP()
{int i,j,ret=0;nxt[0]=-1,i=0,j=-1;while(i<l2){if(j==-1||T[i]==T[j]) nxt[++i]=++j;else j=nxt[j];}i=j=0;while(i<l1){if(j==-1||S[i]==T[j]) i++,j++;else j=nxt[j];if(j==l2) ret++;}return ret;
}
void dfs(int x,int r1,int r2)
{f1.updata(f1.p[r1],1),f2.updata(f2.p[r2],1);int i,a;for(i=0;i<(int)b1[x].size();i++){a=b1[x][i].org;q[a].ans+=b1[x][i].k*(f1.query(f1.q[q[a].a])-f1.query(f1.p[q[a].a]-1));}for(i=0;i<(int)b2[x].size();i++){a=b2[x][i].org;q[a].ans+=b2[x][i].k*(f2.query(f2.q[q[a].b])-f2.query(f2.p[q[a].b]-1));}for(i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[0][x]) dfs(to[i],a1[r1].ch[val[i]],a2[r2].ch[val[i]]);f1.updata(f1.p[r1],-1),f2.updata(f2.p[r2],-1);
}
inline int rd()
{int ret=0,f=1; char gc=getchar();while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();return ret*f;
}
int main()
{n=rd(),m=rd();int i,j,a,b,u;memset(head,-1,sizeof(head));for(i=1;i<n;i++) a=rd(),b=rd(),scanf("%s",T),add(a,b,T[0]-'a'),add(b,a,T[0]-'a');dep[1]=1,getfa(1);for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1;for(j=1;(1<<j)<=n;j++) for(i=1;i<=n;i++) fa[j][i]=fa[j-1][fa[j-1][i]];t1=t2=1;for(i=1;i<=m;i++){q[i].u=rd(),q[i].v=rd(),q[i].top=lca(q[i].u,q[i].v);scanf("%s",T),l2=strlen(T);for(u=1,j=0;j<l2;j++){b=T[j]-'a';if(!a1[u].ch[b]) a1[u].ch[b]=++t1;u=a1[u].ch[b];}q[i].a=u;for(u=1,j=l2-1;j>=0;j--){b=T[j]-'a';if(!a2[u].ch[b]) a2[u].ch[b]=++t2;u=a2[u].ch[b];}q[i].b=u;if(q[i].top!=q[i].u&&q[i].top!=q[i].v){b=min(l2-1,dep[q[i].u]-dep[q[i].top]),l1=b;for(a=0,j=FA(q[i].u,dep[q[i].u]-dep[q[i].top]-b);j!=q[i].top;a++,j=fa[0][j]) S[a]=from[j]+'a';b=min(l2-1,dep[q[i].v]-dep[q[i].top]),l1+=b;for(a=l1-1,j=FA(q[i].v,dep[q[i].v]-dep[q[i].top]-b);j!=q[i].top;a--,j=fa[0][j]) S[a]=from[j]+'a';q[i].ans+=KMP();}if(dep[q[i].v]-dep[q[i].top]>=l2)b1[q[i].v].push_back(node(i,1)),b1[FA(q[i].v,dep[q[i].v]-dep[q[i].top]-l2+1)].push_back(node(i,-1));if(dep[q[i].u]-dep[q[i].top]>=l2)b2[q[i].u].push_back(node(i,1)),b2[FA(q[i].u,dep[q[i].u]-dep[q[i].top]-l2+1)].push_back(node(i,-1));}f1.a=a1,f2.a=a2,f1.tot=t1,f2.tot=t2;f1.build(),f2.build();dfs(1,1,1);for(i=1;i<=m;i++) printf("%d\n",q[i].ans);return 0;
}//12 3 1 2 w 2 3 w 3 4 x 4 5 w 5 6 w 6 7 x 7 8 w 8 9 w 9 10 x 10 11 w 11 12 w 1 7 wwx 1 12 www 1 12 w
//8 1 1 2 a 2 3 b 3 4 a 1 5 b 5 6 a 6 7 b 7 8 a 3 7 ab
转载于:https://www.cnblogs.com/CQzhangyu/p/7749512.html
【BZOJ4231】回忆树 离线+fail树+KMP相关推荐
- SPOJ - DQUERY D-query(莫队/线段树+离线/主席树)
题目链接:点击查看 题目大意:给出一个由n个数组成的序列,再给出m次查询,每次查询区间[l,r]中有多少个不同的数 题目分析:莫队模板题,直接套板子就好了 有点意思的是函数返回值为布尔类型,然后没有r ...
- [POI2005][luogu3462] SZA-Template [fail树]
题面 传送门 思路 首先,我们观察一下这个要求的"模板串",发现它有如下性质: 1.一个模板串$A$是要求的文本串$B$的公共前后缀 2.如果一个模板串$A$有另一个模板串$B$( ...
- fail树(bzoj 3172: [Tjoi2013]单词)
3172: [Tjoi2013]单词 Time Limit: 10 Sec Memory Limit: 512 MB Submit: 4223 Solved: 2051 [Submit][Stat ...
- HDU - 7084 Pty loves string kmp + fail树 + 主席树
传送门 文章目录 题意: 思路: 题意: 给你一个字符串sss,有qqq个询问,每次给x,yx,yx,y代表取sss的前xxx个字符和后yyy个字符拼接起来得到ttt,输出ttt在sss中出现的次数. ...
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 2545 Solved: 1419 [Submit][S ...
- bzoj 2434 [Noi2011]阿狸的打字机(AC自动机+fail树+dfs序+树状数组)
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 3521 Solved: 1913 [Submit][S ...
- BZOJ 2434: [Noi2011]阿狸的打字机 ACAM+fail树
title BZOJ 2434 LUOGU 2414 Description 打字机上只有 \(28\) 个按键,分别印有 \(26\) 个小写英文字母和 B.P 两个字母,是这样工作的: 输入小写字 ...
- P5357 【模板】AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数)
P5357 [模板]AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数) 传送门 形式上,AC 自动机基于由若干模式串构成的 Trie 树,并在此之上增加了一些 fail 边:本质 ...
- CodeForces - 1437G Death DBMS(AC自动机fail树上树链剖分建线段树/暴跳fail)
题目链接:点击查看 题目大意:给出 n 个模式串,每个模式串初始时的权值为 0,然后有 m 次操作: 1 i x:将第 i 个模式串的权值修改为 x 2 s:给出一个字符串 s,询问字符串 s 作为主 ...
最新文章
- 一张图系列——为什么在DllMain里面创建了线程并Wait会卡死
- 【Linux系列】【基础版】第二章 文件、目录管理
- 用matlab求残余误差,matlab在测量误差分析中的应用
- 关于 Fatal NI connect error 12170
- java 课后习题 随机数统计
- 孩子哭的时候大人应该怎么办?
- spring引入properties变量报错
- 年薪百万是社会认同,更是自身价值体现
- Python中各种括号的区别、用途及使用方法
- 萤火虫(FA)算法(附完整Matlab代码,可直接复制)
- web前端数据可视化框架汇总
- ktv点歌系统服务器破解,欧凯KTV卡拉OK点歌系统
- 房屋租赁合同主要内容是那些
- 新电脑安装系统时提示 File:\Boot\BCD Status:0xc000000e 错误解决方案
- Joint Pose and Expression Modeling for Facial Expression Recognition 论文翻译
- 【html+css】
- java 导出word 含表格_poi 导出word,导出表格(复杂表格合并行列)解决方法
- MonoRail学习笔记四:MonoRail基本流程分析
- 习题 于歆杰 电路_清华大学 电路原理 于歆杰 60讲视频教程
- 「鸡尾酒排序」不会?每天一遍,排序再见【超详细】
热门文章
- Eclipse 创建 Java 包
- 十二. 一步步破解JEB 2.0demo版二
- [转]Entity Framework走马观花之把握全局
- 超级数学计算机,超级计算器+
- linux 防火墙开机启动项,Ubuntu 9.10下实现Firestarter网络防火墙自启动
- 网上的一篇spring security详解教程,觉得不错,转过来了
- python统计文本中单词出现次数
- win7关闭开机启动项_电脑开机全是各种广告?来看看我怎么解决的吧
- Html 内联元素、外联元素 和 可变元素
- vue 定义全局函数