题目链接:点击查看

题目大意:给定一个只含小写字母的字符串 sss 和 qqq 次询问,每次询问给定一个字符串,以 s[l..r]s[l..r]s[l..r] 的形式给出,判断 sss 中是否存在两个或多个出现的有重叠部分的给定子串。比如在 “ababa”“ababa”“ababa” 中,两个 “aba”“aba”“aba” 子串就重叠于中间的字母 “a”“a”“a”,而两个 “ab”“ab”“ab” 子串就没有发生重叠。TTT 组数据。

题目分析:对字符串 sss 建立 SAMSAMSAM 然后建出 parerentparerentparerent 树,问题就转换为了子串 s[l:r]s[l:r]s[l:r] 所在的节点,是否存在着相邻的两个 endposendposendpos 距离小于 r−l+1r-l+1r−l+1

针对上面的问题,可以用 setsetset 启发式合并预处理出任意一个节点中相邻两个 endposendposendpos 的最小值,时间复杂度是 O(nlog2n)O(nlog^2n)O(nlog2n) 的

对于每次查询,我们只需要从 s[1:r]s[1:r]s[1:r] 不断跳 fatherfatherfather 直到 s[l:r]s[l:r]s[l:r] 所在的区间就可以了,这里可以用树上倍增优化,时间复杂度是 O(qlogn)O(qlogn)O(qlogn) 的

代码:

// Problem: 重叠的子串
// Contest: HDOJ
// URL: https://acm.hdu.edu.cn/showproblem.php?pid=7091
// Memory Limit: 524 MB
// Time Limit: 20000 ms
//
// Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f;
}
template<typename T>
inline void write(T x)
{if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e5+100;
char s[N];
int tot,last,dp[N<<1][20],val[N<<1],pos[N];
vector<int>node[N<<1];
set<int>endpos[N<<1];
struct Node
{int ch[26];int fa,len;
}st[N<<1];
inline int newnode()
{tot++;for(int i=0;i<26;i++)st[tot].ch[i]=0;st[tot].fa=st[tot].len=0;node[tot].clear(),endpos[tot].clear();val[tot]=inf;return tot;
}
void add(int x)
{int p=last,np=last=newnode();st[np].len=st[p].len+1;while(p&&!st[p].ch[x])st[p].ch[x]=np,p=st[p].fa;if(!p)st[np].fa=1;else{int q=st[p].ch[x];if(st[p].len+1==st[q].len)st[np].fa=q;else{int nq=newnode();st[nq]=st[q]; st[nq].len=st[p].len+1;st[q].fa=st[np].fa=nq;while(p&&st[p].ch[x]==q)st[p].ch[x]=nq,p=st[p].fa;//向上把所有q都替换成nq}}
}
void dfs(int u,int fa) {dp[u][0]=fa;for(int i=1;i<20;i++) {dp[u][i]=dp[dp[u][i-1]][i-1];}for(auto v:node[u]) {dfs(v,u);val[u]=min(val[u],val[v]);if(endpos[u].size()<endpos[v].size()) {swap(endpos[u],endpos[v]);}for(auto it:endpos[v]) {auto itt=endpos[u].lower_bound(it);if(itt!=endpos[u].end()) {val[u]=min(val[u],*itt-it);}if(itt!=endpos[u].begin()) {itt--;val[u]=min(val[u],it-*itt);}endpos[u].insert(it);}}
}
void build() {for(int i=1;i<=tot;i++) {node[st[i].fa].push_back(i);}dfs(1,0);
}
int get_fa(int u,int len) {for(int i=19;i>=0;i--) {if(st[dp[u][i]].len>=len) {u=dp[u][i];}}return u;
}
void init()
{last=1;tot=0;newnode();
}
int main()
{#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);int w;cin>>w;while(w--) {init();int n,m;scanf("%d%d%s",&n,&m,s+1);for(int i=1;i<=n;i++) {add(s[i]-'a');pos[i]=last;endpos[last].insert(i);}build();while(m--) {int l,r;scanf("%d%d",&l,&r);int len=r-l+1;int fa=get_fa(pos[r],len);if(val[fa]<len) {puts("Yes");} else {puts("No");}}}return 0;
}

HDU - 7091 重叠的子串(后缀自动机+set启发式合并+树上倍增)相关推荐

  1. 2021CCPC华为云挑战赛:HDU 7091 重叠的子串(SAM + 线段树合并)

    重叠的子串 给定一个长度为n(1≤∣s∣≤105)n(1 \le \mid s \mid \le 10 ^ 5)n(1≤∣s∣≤105)的只由小写字母构成的字符串sss,有m,(1≤m≤106)m, ...

  2. BZOJ 4032: [HEOI2015]最短不公共子串(后缀自动机+记忆化搜索)

    传送门 解题思路 首先需要预处理两个串\(nxt(i)(j)\)表示i位置之后最近的\(j\). 第一问直接对\(b\)建后缀自动机,枚举\(a\)的起点暴力匹配. 第二问枚举\(a\)的起点,\(b ...

  3. 最长公共子串_两个字符串的最长公共子串(后缀自动机)

    // 最长公共子序列(后缀自动机) typedef struct state {int len, link;map<char, int> next; }state;const int MA ...

  4. 【HDU】5197 DZY Loves Orzing 【FFT启发式合并】

    传送门:[HDU]5197 DZY Loves Orzing 题目分析: 首先申明,我不会dpdp方程= =--这个东西给队友找出来了,然后我就是套这个方程做题的Qrz-- 对于这题,因为n2n^2个 ...

  5. BZOJ.4180.字符串计数(后缀自动机 二分 矩阵快速幂/倍增Floyd)

    题目链接 先考虑 假设S确定,使构造S操作次数最小的方案应是:对T建SAM,S在SAM上匹配,如果有S的转移就转移,否则操作数++,回到根节点继续匹配S.即每次操作一定是一次极大匹配. 简单证明:假设 ...

  6. Codeforces.666E.Forensic Examination(广义后缀自动机 线段树合并)

    题目链接 \(Description\) 给定串\(S\)和\(m\)个串\(T_i\).\(Q\)次询问,每次询问\(l,r,p_l,p_r\),求\(S[p_l\sim p_r]\)在\(T_l\ ...

  7. Codeforces.700E.Cool Slogans(后缀自动机 线段树合并 DP)

    题目链接 \(Description\) 给定一个字符串\(s[1]\).一个字符串序列\(s[\ ]\)满足\(s[i]\)至少在\(s[i-1]\)中出现过两次(\(i\geq 2\)).求最大的 ...

  8. 【CF666E】Forensic Examination - 广义后缀自动机+线段树合并

    广义SAM专题的最后一题了--呼 题意: 给出一个长度为$n$的串$S$和$m$个串$T_{1\cdots m}$,给出$q$个询问$l,r,pl,pr$,询问$S[pl\cdots pr]$在$T_ ...

  9. 【CF700E】Cool Slogans【后缀自动机】【可持久化线段树合并】【树上倍增】

    传送门 题意:给定字符串SSS,求一堆字符串s1,s2,s3,...,sks_1,s_2,s_3,...,s_ks1​,s2​,s3​,...,sk​,满足s1s_1s1​是SSS的子串,且sis_i ...

最新文章

  1. 网传京东某程序员因压力太大,在商品页面置入骂人代码!京东辟谣:不关我们的事,外部商家干的!...
  2. HDU-3177 Crixalis's Equipment 贪心
  3. 启动weblogic的错误:Could not obtain an exclusive lock to the embedded LDAP data files directory...
  4. linux awk 分组统计
  5. 如何轻松学习Python数据分析?
  6. 以ABP为基础架构的一个中等规模的OA开发日志
  7. [Vue.js] Vuex的使用
  8. php 保存错误日志,PHP中把错误日志保存在系统日志中_PHP教程
  9. FTT字体绘制,2D阶段
  10. BP神经网络算法基本原理,基于bp的神经网络算法
  11. 个性化不和谐帐户的8种方法
  12. 多省市区“十四五”规划布局交通新基建
  13. unbalanced calls to begin/end appearance transitions for uiviewcontroller的解决方法
  14. 阿里云安全中心是什么?提供哪些防护?
  15. 装了xmapp还需要装mysql吗_安装xamp之后,appach、mysql等问题的总结
  16. python 给定一个字符串,输出所有指定长度为n的子串,没有则输出-1
  17. B细胞介导的体液免疫
  18. Python操作*.cfg配置文件
  19. 了解信息学竞赛流程,快速入门!
  20. 三元(三目)运算符解释

热门文章

  1. 百题大冲关系列课程更新啦!这次是 Golang
  2. 5个教程教你学会写爬虫!(Python)
  3. Java文件能编译成lib吗_Makefile用于将一些.cpp和.h编译成lib
  4. mysql hive 内置函数_Hive 内置函数
  5. pytorch | transpose、permute、view、contiguous、is_contiguous、reshape
  6. 函数式接口作为方法的参数【应用】
  7. SpringMVC流程图示
  8. web应用的目录结构
  9. ES6新特性之函数优化-箭头函数
  10. 百万数据报表读取:解决方案及原理分析