哈希也是有技巧的。不然很容易错。

匹配串范围是1e6的,所以普通hash错误概率也是很大的

所以就要利用匹配的特性(长度与匹配串一一对应)来hash,这样错误概率会小,相当于hash挂链吧。

一开始写的每个前缀hash存位置。这样一个hash里就有1e6个值。

码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<cstring>
#define P 2147483647
#define ll long long
#define D(x) cout<<x<<" ";
using namespace std;
#define N 2000005
#define ll long long
vector<int>v[N];
ll qian[N],hou[N];
int sz[N],fu[N],f[N],g[N],vf[N],vg[N],i,j,n,m,ans,tot,rt,now,T,a,b;
ll ci[N],lin;
char  ch[N],S[N];
bool vis[N];
void dfs(int o,int fa)
{
int i,nd;sz[o]=1;fu[o]=fa;for(i=0;i<v[o].size();i++){nd=v[o][i];if(nd==fa||vis[nd])continue;dfs(nd,o);sz[o]+=sz[nd];}
}
void zzx(int o,int qsz)
{int szcnt=0,i,nd,maxx=qsz;for(i=0;i<v[o].size();i++)if(vis[v[o][i]]==0&&fu[o]!=v[o][i])szcnt+=sz[v[o][i]],maxx=max(maxx,sz[v[o][i]]);if(maxx<=tot/2)rt=o; for(i=0;i<v[o].size();i++){   nd=v[o][i];if(nd==fu[o]||vis[nd])continue;zzx(nd,qsz+1+szcnt-sz[nd]);     }
}
void Dfs(int o,int fa,ll lin,int dis)
{int i,nd;if(qian[dis]==lin&&vg[m-dis%m-1]==now)  //统计答案 ans+=g[m-dis%m-1];  if(hou[dis]==lin&&vf[m-dis%m-1]==now)   //统计答案 ans+=f[m-dis%m-1];   for(i=0;i<v[o].size();i++){nd=v[o][i];if(nd==fa||vis[nd])continue;Dfs(nd,o,(lin+(1ll*(ch[nd]-'A'+1)*ci[dis+1])%P)%P,dis+1);}
}
void dfS(int o,int fa,ll lin,int dis)
{int i,nd;if(qian[dis]==lin)  //统计答案 {if(vf[dis%m]!=now)vf[dis%m]=now,f[dis%m]=0; f[dis%m]++; }if(hou[dis]==lin)   //统计答案 {if(vg[dis%m]!=now)vg[dis%m]=now,g[dis%m]=0;     g[dis%m]++; }for(i=0;i<v[o].size();i++){nd=v[o][i];if(nd==fa||vis[nd])continue;dfS(nd,o,(lin+(1ll*(ch[nd]-'A'+1)*ci[dis+1])%P)%P,dis+1);}
}
void solve(int o)
{now=o;int i,nd,hx=ch[o]-'A'+1;
if(qian[0]==hx)vf[0]=o,f[0]=1;
if(hou[0]==hx)vg[0]=o,g[0]=1;
if(vf[0]==o&&vf[0]==vg[m-1])
ans+=g[m-1];for(i=0;i<v[o].size();i++){nd=v[o][i];if(vis[nd])continue;Dfs(nd,o,(hx+(ch[nd]-'A'+1)*ci[1])%P,1);dfS(nd,o,(hx+(ch[nd]-'A'+1)*ci[1])%P,1);    }
}
void work(int o)
{vis[o]=1;solve(o);int i,nd;for(i=0;i<v[o].size();i++){nd=v[o][i]; if(vis[nd]||sz[nd]<m)continue;
tot=sz[nd]; dfs(nd,o);zzx(nd,0);   dfs(rt,0);
work(rt);   }
}
int main()
{ci[0]=1;for(i=1;i<=100000;i++)ci[i]=(ci[i-1]*27)%P;scanf("%d",&T);while(T--){ans=0;memset(vf,0,sizeof(vf));memset(vg,0,sizeof(vg));    memset(vis,0,sizeof(vis));for(i=1;i<=100000;i++)v[i].clear();scanf("%d%d",&n,&m);for(i=1;i<=n;i++){scanf("%c",&ch[i]);while(ch[i]<'A'||ch[i]>'Z')scanf("%c",&ch[i]);}for(i=1;i<n;i++){scanf("%d%d",&a,&b);v[a].push_back(b);v[b].push_back(a);}for(i=1;i<=m;i++){scanf("%c",&S[i]);while(S[i]<'A'||S[i]>'Z')scanf("%c",&S[i]);}
lin=0;
for(i=0;i<=n;i++)
{lin=(lin*27+1ll*(S[(i%m)+1]-'A'+1))%P;qian[i]=lin;
}
lin=0;
for(i=0;i<=n;i++)
{lin=(lin*27+1ll*(S[(m-i%m-1)+1]-'A'+1))%P;hou[i]=lin;
}       dfs(1,0);tot=n;zzx(1,0);   dfs(rt,0);work(rt);   printf("%d\n",ans); }
}

bzoj4598 [Sdoi2016]模式字符串 hash+点分相关推荐

  1. BZOJ4598: [Sdoi2016]模式字符串

    BZOJ4598 求树上满足某些条件的点对,首先就可以想到点分治. 然后又与什么字符串匹配有关.KMP,AC自动机--KMP,AC自动机--之类的好像不太好用..那就哈希吧! 添加答案的时候有两种情况 ...

  2. Bzoj4598: [Sdoi2016]模式字符串 点分治 哈希

    国际惯例的题面: 这种关于树上路径的题,我也没什么好办法,只好点分治. 考虑当前分治重心为root,如何统计经过分治重心的路径的答案. 我们令prf[i]表示某个点到root的路径(不含root)已经 ...

  3. 【BZOJ4598】[Sdoi2016]模式字符串 树分治+hash

    [BZOJ4598][Sdoi2016]模式字符串 Description 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每 ...

  4. 4598: [Sdoi2016]模式字符串

    4598: [Sdoi2016]模式字符串 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 80  Solved: 37 [Submit][Statu ...

  5. BZOJ.4598.[SDOI2016]模式字符串(点分治 Hash)

    LOJ BZOJ 洛谷 点分治.考虑如何计算过\(rt\)的答案. 记\(pre[i]\)表示(之前的)子树内循环匹配了\(S\)的前缀\(i\)的路径有多少,\(suf[i]\)表示(之前的)子树内 ...

  6. bzoj 4598: [Sdoi2016]模式字符串

    题目描述 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每一位仍然是A到z的大写字母. Alice希望知道,有多少对结点&l ...

  7. [BZOJ 4598][Sdoi2016]模式字符串

    传送门 经典的点分治,hash判断字符串的前缀和后缀: 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define rep(i, ...

  8. 字符串Hash的原理与应用

    字符串Hash无论是在ACM竞赛中还是在工程中都有着广泛的应用,所以很有必要掌握好它的用法.主要分为两个部 分:Hash映射和冲突处理.而本文主要来详细讲解Hash映射的方法及应用,下篇文章将会介绍如 ...

  9. 字符串hash(二)

    从上一届已经讲了字符串hash的方法,hash后怎么用也很重要 文章目录 一.查询子串的hash值 查询子串减去期中一个字符后的hash值 查询两个子串拼接的hash值 **hash的模板(自然溢出) ...

最新文章

  1. elasticsearch使用jetty进行简单的权限控制
  2. python 函数 日期区间_python-如何获取两个日期之间的日期
  3. Hive SQL基础
  4. xml验证 java代码,使用Java代码进行XML验证
  5. 终极指南:如何使用Visual Studio Code进行 Java 开发?
  6. SPI接口比IIC速度快的理解
  7. 鸿蒙os下载到电脑上,鸿蒙系统pc版下载2.0
  8. “约见”面试官系列之常见面试题之第六十二篇之IE和兼容下写法(建议收藏)
  9. SpringBoot 整合 MyCat 实现读写分离
  10. 三国演义人物出场统计代码含义_Python分析《三国演义》人物出场次数,孔明第二,赵云第五...
  11. Spring Boot2.0之性能优化
  12. 路灯干扰者路过时,路灯熄灭的照片
  13. Js参数RSA加密传输,jsencrypt.js的使用
  14. docker-compose listing workers for Build: failed to list workers
  15. Word中大括号内公式左对齐
  16. NRF24L01使用
  17. 填坑记录——扫雷游戏的重置
  18. 4.18耶稣受难日黄金持续跌势(附黄金原油操作建议)
  19. 合成资产赛道风云突变,Linear Finance有望成为最具潜力的黑马
  20. GERL 2020 (WWW)Graph Enhanced Representation Learning for News Recommendation

热门文章

  1. android多个activity绑定一个service,8.1.2 绑定Activity和Service
  2. 红橙Darren视频笔记 仿QQ侧滑效果
  3. c++ 数组置0_09c语言数组详解
  4. python程序多次运行_Python内怎么使同一个.py文件多次运行?
  5. android 自定义域名,Android基于Retrofit2改造的可设置多域名的网络加载框架
  6. 运行linux在de1soc,在DE1-SOC上运行Linux
  7. php exec执行多条命令,小技巧:在PHP中调用多条shell指令
  8. centos6.8 mysql5.6_Centos6.8 Mysql5.6 安装配置教程(转)
  9. createprocess重启程序_win32取CreateProcess启动程序的返回值
  10. Scala go java_Java、Scala和Go语言多线程并发对比测试结果和结论