题目描述

给你一个串S以及一个字符串数组T[1..m],q次询问,每次问S的子串S[pl​..pr​]在T[l..r]中的哪个串里的出现次数最多,并输出出现次数。

如有多解输出最靠前的那一个。

题解

算是道字符串比较套路的题吧。

对模式串建SAM,对所有模式串的所有前缀维护right集合。

然后对于每个询问,倍增找到关键点,查子树众数。

坑:在最匹配串做匹配的时候,要记录匹配长度,如果匹配长度不够询问长度,直接判无解。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 1000009
using namespace std;
typedef long long ll;
int ch[N][],tott,tr[N*],id[N*],ls[N*],rs[N*],ans1,ans2,fa[N],mat[N];
int cnt,last,l[N],tot,head[N],n,p[][N],deep[N],T[N],tag[N];
char s[N],s1[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
void upd(int &cnt,int l,int r,int x){
if(!cnt)cnt=++tott;
if(l==r){tr[cnt]++;id[cnt]=l;return;}
int mid=(l+r)>>;
if(mid>=x)upd(ls[cnt],l,mid,x);
else upd(rs[cnt],mid+,r,x);
tr[cnt]=max(tr[ls[cnt]],tr[rs[cnt]]);
id[cnt]=tr[ls[cnt]]>=tr[rs[cnt]]?id[ls[cnt]]:id[rs[cnt]];
}
int merge(int x,int y,int l,int r){
if(!x||!y)return x^y;
int p=++tott;
if(l==r){tr[p]=tr[x]+tr[y];id[p]=l;return p;}
int mid=(l+r)>>;
ls[p]=merge(ls[x],ls[y],l,mid);rs[p]=merge(rs[x],rs[y],mid+,r);
tr[p]=max(tr[ls[p]],tr[rs[p]]);
id[p]=tr[ls[p]]>=tr[rs[p]]?id[ls[p]]:id[rs[p]];
return p;
}
void query(int cnt,int l,int r,int L,int R){
if(!cnt)return;
if(l>=L&&r<=R){
if(tr[cnt]>ans1){
ans1=tr[cnt];
ans2=id[cnt];
}
return;
}
int mid=(l+r)>>;
if(mid>=L)query(ls[cnt],l,mid,L,R);
if(mid<R)query(rs[cnt],mid+,r,L,R);
}
inline void ins(int x,int id){
if(ch[last][x]){
int p=last,q=ch[last][x];
if(l[p]+==l[q])last=q;
else{
int nq=++cnt;l[nq]=l[p]+;
memcpy(ch[nq],ch[q],sizeof(ch[nq]));
fa[nq]=fa[q];fa[q]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
last=nq;
}
}
else{
int p=last,np=++cnt;l[np]=l[p]+;last=np;
for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np;
if(!p)fa[np]=;
else{
int q=ch[p][x];
if(l[p]+==l[q])fa[np]=q;
else{
int nq=++cnt;l[nq]=l[p]+;
memcpy(ch[nq],ch[q],sizeof(ch[nq]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
}
}
}
upd(T[last],,n,id);
}
struct edge{int n,to;}e[N];
inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
void dfs(int u){
for(int i=;(<<i)<=deep[u];++i)p[i][u]=p[i-][p[i-][u]];
for(int i=head[u];i;i=e[i].n){
int v=e[i].to;deep[v]=deep[u]+;p[][v]=u;
dfs(v);T[u]=merge(T[u],T[v],,n);
}
}
int main(){
scanf("%s",s+);
n=rd();cnt=;
for(int i=;i<=n;++i){
last=;
scanf("%s",s1);int len=strlen(s1);
for(int j=;j<len;++j)ins(s1[j]-'a',i);
}
for(int i=;i<=cnt;++i)if(fa[i])add(fa[i],i);
dfs();int len=strlen(s+),now=,le=;
for(int i=;i<=len;++i){
while(now&&!ch[now][s[i]-'a'])now=fa[now],le=l[now];
if(!now)now=;
if(ch[now][s[i]-'a'])now=ch[now][s[i]-'a'],le++;
tag[i]=now;mat[i]=le;
}
int q=rd(),l1,r1,l2,r2;
while(q--){
l2=rd();r2=rd();l1=rd();r1=rd();
int x=tag[r1];
if(!x||mat[r1]<r1-l1+){
printf("%d 0\n",l2);continue;
}
for(int i=;i>=;--i)if(l[p[i][x]]>=r1-l1+)x=p[i][x]; ans1=;ans2=l2;;
query(T[x],,n,l2,r2);
printf("%d %d\n",ans2,ans1);
}
return ;
}

CodeForces666E Forensic Examination的更多相关文章

  1. 【Codeforces666E】Forensic Examination 后缀自动机 + 线段树合并

    E. Forensic Examination time limit per test:6 seconds memory limit per test:768 megabytes input:stan ...

  2. Codeforces 666E E - Forensic Examination SA + 莫队 + 线段树

    E - Forensic Examination 我也不知道为什么这个复杂度能过, 而且跑得还挺快, 数据比较水? 在sa上二分出上下界, 然后莫队 + 线段树维护区间众数. #include< ...

  3. 【CF666E】Forensic Examination 广义后缀自动机+倍增+线段树合并

    [CF666E]Forensic Examination 题意:给你一个字符串s和一个字符串集合$\{t_i\}$.有q个询问,每次给出$l,r,p_l,p_r$,问$s[p_l,p_r]$在$t_l ...

  4. 【CF666E】Forensic Examination(后缀自动机,线段树合并)

    [CF666E]Forensic Examination(后缀自动机,线段树合并) 题面 洛谷 CF 翻译: 给定一个串\(S\)和若干个串\(T_i\) 每次询问\(S[pl..pr]\)在\(T_ ...

  5. Codeforces 666E Forensic Examination SAM or SA+线段树合并

    E. Forensic Examination http://codeforces.com/problemset/problem/666/E 题目大意:给模式串S以及m个特殊串,q个询问,询问S的子串 ...

  6. CF 666E Forensic Examination 【SAM 倍增 线段树合并】

    CF 666E Forensic Examination 题意: 给出一个串\(s\)和\(n\)个串\(t_i\),\(q\)次询问,每次询问串\(s\)的子串\(s[p_l:p_r]\)在串\(t ...

  7. 【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并

    题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r ...

  8. Codeforces 666E Forensic Examination

    题意:给定主串s和m个模式串,每次询问[l,r]的模式串中出现s[pl...pr]次数最多的串和次数. 这题挺简单的,先把所有模式串拿来建广义后缀自动机,询问相当于子树众数,用线段树合并即可. 那我为 ...

  9. [CF 666E] Forensic Examination

    Description 传送门 Solution 对 \(T[1..m]\) 建立广义后缀自动机,离线,找出代表 \(S[pl,pr]\) 的每个节点,线段树合并. Code #include < ...

随机推荐

  1. 总结:BGP和静态路由并存,达到故障自动倒换的目的。

    总体结论: 在上云的场景中,客户需要本地数据中心到云上VPC,出现网络故障时做到自动倒换,保证业务不中断. 一.客户需求 1.客户有总厂.分厂.总厂是通过专线和VPN连接上云,分厂是通过专线先连接到总 ...

  2. 使用Python下载工具you-get下载媒体文件

    You-Get是一个基于 Python 3 的下载工具.使用 You-Get 可以很轻松的下载到网络上的视频.图片及音乐. 使用you-get下载媒体文件 1.安装Python(步骤详情见另一篇文章) ...

  3. Android 简单实现控件的拖动

    控件的拖动,使用到一个监听事件 setOnTouchListener:XML代码: <?xml version="1.0" encoding="utf-8" ...

  4. [Python][小知识][NO.5] 使用 Pyinstaller 打包成.exe文件

    1.安装 pyinstaller 插件 cmd命令:pip install PyInstaller PS . o.o 不知道 easy_install 的百度吧. 2.pyinstaller 简介 他 ...

  5. Linux 查看进程消耗内存情况总结

    在Linux中,有很多命令或工具查看内存使用情况,今天我们来看看如何查看进程消耗.占用的内存情况,Linux的内存管理和相关概念要比Windows复杂一些.在此之前,我们需要了解一下Linux系统下面 ...

  6. SQL Server中LIKE %search_string% 走索引查找(Index Seek)浅析

      在SQL Server的SQL优化过程中,如果遇到WHERE条件中包含LIKE '%search_string%'是一件非常头痛的事情.这种情况下,一般要修改业务逻辑或改写SQL才能解决SQL执行 ...

  7. macos 远程 windows 10

    使用的工具:Parallels Client 免费,可以从windows store 免费下载: 只有这个最好用,希望能帮到你.和原生的windows 远程桌面功能很像:

  8. Cs231n课堂内容记录-Lecture 7 神经网络训练2

    Lecture 7  Training Neural Networks 2 课堂笔记参见:https://zhuanlan.zhihu.com/p/21560667?refer=intelligent ...

  9. LeetCode算法题-Degree of an Array(Java实现)

    这是悦乐书的第294次更新,第312篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第162题(顺位题号是697).给定一个由正整数组成的非空数组,该数组的度数被定义为任意 ...

  10. centos7下kubernetes(15。kubernetes-外网访问service)

    kubernetes提供了多种类型的service,默认是cluster IP ClusterIP cluster内部IP对外提供服务,只有cluster内的节点和pod可访问,这是默认的servic ...