• 题解:

    • 树上的串匹配,模式串的总长$|S|$,令$\overline {S} $为$S$的反串;
    • 对$S$和$\overline {S} $分别建自动机
    • $u -> v$可以分成三个部分去统计
    • ①跨越了$lca(u, v)$的部分,长度不会超过$2|S|$,$kmp$暴力统计答案;
    • ②$(u,lca)$上不跨越$lca$的部分,差分变成两个到根的询问;
    • ②$(lca,v)$上不跨越$lca$的部分,差分变成两个到根的询问;
    • $dfs$原树并记录走到两个自动机的节点$x / y$,$BIT$维护$fail$树的子树和:
    • 进入时$add(x / y,1)$,回溯时$add(x /  y,-1)$;
    • ②在$\overline {S} $里查,①在$S$里查即可处理所有询问;
    • (突然发现似乎不用建两个自动机,直接建在一起就好了TAT所以别学大米饼丑陋的代码)
    • 一个弱化版:bzoj3881,另外树剖$lca$常数小,好些,点分治常用$rmq$求$lca$;
    •  #include<bits/stdc++.h>
      #define rg register
      #define il inline
      using namespace std;
      const int N=,M=;
      int n,m,o=,hd[N],Hd[N],O=,tp[N],sz[N],sn[N],dfn[N],idx;
      int q[N],head,tail,fa[N],f[N],pos[N],dep[N],ans[N];
      struct Edge{int v,nt,c;}E[N<<];
      struct Qury{int p,x,y,nt;}Q[N<<];
      char s[N],t[N],fm[N];
      il void adde(int u,int v,int c){
      E[o]=(Edge){v,hd[u],c};hd[u]=o++;
      E[o]=(Edge){u,hd[v],c};hd[v]=o++;
      }
      il void addq(int u,int p,int x,int y){
      Q[O]=(Qury){p,x,y,Hd[u]};Hd[u]=O++;
      }
      void dfs1(int u,int F){
      sz[u]=;sn[u]=;
      dep[u]=dep[fa[u]=F]+;
      for(rg int i=hd[u];i;i=E[i].nt){
      int v=E[i].v;
      if(v==F)continue;
      fm[v]=E[i].c+'a';
      dfs1(v,u);
      sz[u]+=sz[v];
      if(sz[v]>sz[sn[u]])sn[u]=v;
      }
      }
      void dfs2(int u,int T){
      dfn[pos[u]=++idx]=u;tp[u]=T;
      if(sn[u])dfs2(sn[u],T);
      for(rg int i=hd[u];i;i=E[i].nt){
      int v=E[i].v;
      if(v==fa[u]||v==sn[u])continue;
      dfs2(v,v);
      }
      }
      il int go(int u,int d){
      int tu=tp[u];
      while(dep[u]-dep[tu]<d){
      d-=dep[u]-dep[tu]+;
      u=fa[tu],tu=tp[u];
      }
      return dfn[pos[tu]+dep[u]-dep[tu]-d];
      }
      il int lca(int u,int v){
      int tu=tp[u],tv=tp[v];
      while(tu!=tv)if(dep[tu]>dep[tv])u=fa[tu],tu=tp[u];
      else v=fa[tv],tv=tp[v];
      return dep[u]<dep[v]?u:v;
      }
      il int kmp(int x,int y,int z,int ls){
      int lt=,tl=,re=;
      while(dep[x]>dep[z])t[++lt]=fm[x],x=fa[x];
      tl=lt=lt+dep[y]-dep[z];
      while(dep[y]>dep[z])t[tl--]=fm[y],y=fa[y];
      if(lt<ls)return ;
      f[]=f[]=;
      for(rg int i=,j=;i<ls;f[++i]=j){
      while(j&&s[i+]!=s[j+])j=f[j];
      if(s[i+]==s[j+])j++;
      }
      for(rg int i=,j=;i<=lt;i++){
      while(j&&t[i]!=s[j+])j=f[j];
      if(t[i]==s[j+])j++;
      if(j==ls)re++,j=f[j];
      }
      return re;
      }
      struct AC{
      int cnt,fl[M],fa[M],st[M],ed[M],idx,c[M],ch[M][],pos[N],hd[N],o;
      struct Edge{int v,nt;}E[N];
      il void adde(int u,int v){E[o]=(Edge){v,hd[u]};hd[u]=o++;}
      il void add(int x,int y){for(;x<=idx;x+=x&-x)c[x]+=y;}
      il int ask(int x){int re=;for(;x;x-=x&-x)re+=c[x];return re;}
      il void ins(int cur,int l){
      int x=;
      for(int i=,y;i<=l;i++){
      if(!ch[x][y=s[i]-'a'])ch[x][y]=++cnt;
      x=ch[x][y];
      }pos[cur]=x;
      }
      il void dfs(int u){
      st[u]=++idx;
      for(rg int i=hd[u];i;i=E[i].nt)dfs(E[i].v);
      ed[u]=idx;
      }
      il void bfs(){
      o=;head=tail=;
      for(int i=;i<;i++)if(ch[][i]){
      q[++tail]=ch[][i];
      adde(,ch[][i]);
      }
      while(head<tail){
      int u=q[++head];
      for(rg int i=;i<;i++){
      int&v=ch[u][i];
      if(!v){v=ch[fl[u]][i];continue;}
      fl[v]=ch[fl[u]][i];
      q[++tail]=v;
      adde(fl[v],v);
      }
      }
      dfs();
      }
      il int que(int x){return ask(ed[pos[x]]) - ask(st[pos[x]]-);}
      }ac[];
      void dfs3(int u,int y0,int y1){
      ac[].add(ac[].st[y0],);
      ac[].add(ac[].st[y1],);
      for(int i=Hd[u];i;i=Q[i].nt){
      ans[Q[i].x]+=ac[Q[i].p].que(Q[i].x)*Q[i].y;
      }
      for(int i=hd[u];i;i=E[i].nt){
      int v=E[i].v , c=E[i].c;
      if(E[i].v==fa[u])continue;
      dfs3(v,ac[].ch[y0][c],ac[].ch[y1][c]);
      }
      ac[].add(ac[].st[y0],-);
      ac[].add(ac[].st[y1],-);
      }
      int main(){
      #ifndef ONLINE_JUDGE
      freopen("bzoj4231.in","r",stdin);
      freopen("bzoj4231.out","w",stdout);
      #endif
      scanf("%d%d",&n,&m);
      for(rg int i=;i<n;i++){
      int u,v;
      scanf("%d%d%s",&u,&v,s+);
      adde(u,v,s[]-'a');
      }
      dfs1(,);dfs2(,);
      for(rg int i=;i<=m;i++){
      int u,v,w,l,t1,t2;
      scanf("%d%d%s",&u,&v,s+);
      w=lca(u,v);
      l=strlen(s+);
      t1=go(u,max(,dep[u]-dep[w]-l+));
      t2=go(v,max(,dep[v]-dep[w]-l+));
      ans[i]+=kmp(t1,t2,w,l);
      ac[].ins(i,l);
      for(rg int j=;j<=l>>;j++)swap(s[j],s[l-j+]);
      ac[].ins(i,l);
      if(t1!=u)addq(u,,i,),addq(t1,,i,-);
      if(t2!=v)addq(v,,i,),addq(t2,,i,-);
      }
      ac[].bfs();
      ac[].bfs();
      dfs3(,,);
      for(rg int i=;i<=m;i++){printf("%d\n",ans[i]);}
      return ;
      }

      bzoj4231

$lca(q[i-1],q[i])$

【bzoj4231】回忆树的更多相关文章

  1. BZOJ4231 : 回忆树

    一个长度为$|S|$的串在树上匹配有两种情况: 1.在LCA处转弯,那么这种情况只有$O(|S|)$次,暴力提取出长度为$2|S|$的链进行KMP即可. 2.不转弯,那么可以拆成两个到根路径的询问. ...

  2. 并不对劲的bzoj4231: 回忆树

    题目大意 \(n\)个点的树,每条边上有一个小写字母. 操作:给定2个点\(u\),\(v\)(\(u\)可能等于\(v\))和一个非空字符串\(s\),问从\(u\)到\(v\)的简单路径上的所有边 ...

  3. 【BZOJ4231】回忆树 离线+fail树+KMP

    [BZOJ4231]回忆树 Description 回忆树是树. 具体来说,是n个点n-1条边的无向连通图,点标号为1~n,每条边上有一个字符(出于简化目的,我们认为只有小写字母). 对一棵回忆树来说 ...

  4. 「模拟赛20180306」回忆树 memory LCA+KMP+AC自动机+树状数组

    题目描述 回忆树是一棵树,树边上有小写字母. 一次回忆是这样的:你想起过往,触及心底--唔,不对,我们要说题目. 这题中我们认为回忆是这样的:给定 \(2\) 个点 \(u,v\) (\(u\) 可能 ...

  5. 哈夫曼(huffman)树和哈夫曼编码

    哈夫曼树 哈夫曼树也叫最优二叉树(哈夫曼树) 问题:什么是哈夫曼树? 例:将学生的百分制成绩转换为五分制成绩:≥90 分: A,80-89分: B,70-79分: C,60-69分: D,<60 ...

  6. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  7. LOJ#510 北校门外的回忆(找性质+倍增+线段树)

    这题一场模拟赛我们出了弱化版(n<=1e6),抄题面给的程序能拿到71分的好成绩 其实后面的29分是加了几个1e9的数据卡人 这糟老头子真是坏得很 正解我们机房看了三天 在这里感谢这篇题解的作者 ...

  8. LOJ#510. 「LibreOJ NOI Round #1」北校门外的回忆(线段树)

    题面 传送门 题解 感谢\(@M\_sea\)的代码我总算看懂题解了-- 这个操作的本质就是每次把\(x\)的\(k\)进制最低位乘\(2\)并进位,根据基本同余芝士如果\(k\)是奇数那么最低位永远 ...

  9. LOJ 北校门外的回忆 倍增+线段树

    正解:倍增+线段树 解题报告: 传送门! $umm$这题有个对正解毫无启发的部分分还有个正解,都挺神仙的所以我都写了趴$QAQ$ 先说部分分 可以考虑把$x$向$x+lowbit(x)$连边,然后当$ ...

随机推荐

  1. java程序设计课程实验报告1

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计   班级:1353       姓名:陈都  学号:20135328 成绩:             指导 ...

  2. 20145214 《网络对抗技术》 MSF基础应用

    20145214 <网络对抗技术> MSF基础应用 1.实验后回答问题--用自己的话解释什么是exploit,payload,encode 如果把MSF比作一把枪的话,payload应该是 ...

  3. Sprint4

    进展:今天一天满课,晚上也没有做什么,所以今天一天没什么进展. 燃尽图:

  4. JAVA异常架构图及常见面试题

    红色为检查异常,就是eclipse要提示你是try catch 还是throws. 非检查异常,就是/0,nullpointexception,数据越界访问indexOfOutBounds 异常 错误 ...

  5. 实现二叉树(search)

    ★实验任务 可怜的 Bibi 刚刚回到家,就发现自己的手机丢了,现在他决定回头去搜索 自己的手机. 现在我们假设 Bibi 的家位于一棵二叉树的根部.在 Bibi 的心中,每个节点 都有一个权值 x, ...

  6. 20_集合_第20天(Map、可变参数、Collections)_讲义

    今日内容介绍 1.Map接口 2.模拟斗地主洗牌发牌 01Map集合概述 A:Map集合概述: 我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式 ...

  7. [转帖] go的import 语法

    package 的导入语法写 Go 代码的时经常用到 import 这个命令用来导入包,参考如下: import( "fmt" ) 然后在代码里面可以通过如下的方式调用: fmt. ...

  8. ACM数论之旅1---素数(万事开头难(>_<))

    前言:好多学ACM的人都在问我数论的知识(其实我本人分不清数学和数论有什么区别,反正以后有关数学的知识我都扔进数论分类里面好了) 于是我就准备写一个长篇集,把我知道的数论知识和ACM模板都发上来(而且 ...

  9. SpringBoot(十)_springboot集成Redis

    Redis 介绍 Redis是一款开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存也可持久化的日志型.Key-Value高性能数据库. 数据模型 Redis 数据模型不仅与关系数据 ...

  10. GIT的使用方法

    GIT的使用方法 1.电脑首先安装GIT, 2.在官网注册GitHub账号. 一,使用git在控制台进行本地操作 1.打开GitBash 2.填写用户名和邮箱作为标识分别执行以下命令: git/ co ...