题意

  给你一个串 $S$ 以及一个字符串数组 $T[1..m]$ , $q$ 次询问,每次问 $S$ 的子串 $S[p_l..p_r]$ 在 $T[l..r]$ 中的哪个串里的出现次数最多,并输出出现次数。如有多解输出最靠前的那一个。

题解

  神仙题……虽然的确是好题……然而码量好大……好麻烦……因为一个sb错误调了一个下午

  先膜一波zsy大佬……%%%

  首先先把$T$给建出一个广义$SAM$。考虑每一个询问的$p_r$,如果在$SAM$上匹配到了一个节点,那么这个子串$S[p_l,p_r]$一定是这个节点的一个祖先(然后如果根本匹配不到的话直接跳过)

  然后可以考虑倍增找到祖先,只要找到满足$len_u>=p_r-p_l+1$的最上面的节点就好了

  然后考虑如何表示这个节点在$[l,r]$范围内在哪些串出现了多少次,以及出现次数的最大值。区间查询可以考虑用线段树。对于每一个$SAM$上的节点,我们对他建一棵线段树,表示有这个节点代表的字符串在$T$中的出现次数。然后通过倍增找到节点,在线段树上查询就是了

  于是直接把串$S$放到$SAM$上跑,然后在每一个节点记录一下有哪些询问在这个点上,一波$dfs$的时候顺便合并父亲和儿子的出现次数的区间,并求出答案

  说的好像很简单……然而真的码得有点想哭……

 //minamoto
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while((ch=getchar())<''||ch>'')
(ch=='-')&&(flag=true);
for(res=num;(ch=getchar())>=''&&ch<='';res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(int x,char ch){
if(C><<)Ot();if(x<)sr[++C]=,x=-x;
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);sr[++C]=ch;
}
const int N=5e5+;
struct data{
int x,y;
inline bool operator <(const data &b)const
{return x<b.x||x==b.x&&y>b.y;}
}ans[N];
int L[N*],R[N*];data V[N*];
struct node{int l,r,pl,pr;}q[N];
int n,m,Q,last=,cnt=,ch[N][],fa[][N],l[N],rt[N],tot=;
int nxt[][N],head[][N];
char s[N],t[N];
void ins(int c){
int p=last,np=++cnt;last=np,l[np]=l[p]+;
for(;p&&!ch[p][c];p=fa[][p]) ch[p][c]=np;
if(!p) fa[][np]=;
else{
int q=ch[p][c];
if(l[q]==l[p]+) fa[][np]=q;
else{
int nq=++cnt;l[nq]=l[p]+;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[][nq]=fa[][q],fa[][q]=fa[][np]=nq;
for(;ch[p][c]==q;p=fa[][p]) ch[p][c]=nq;
}
}
}
void modify(int &now,int l,int r,int x){
now=++tot;
if(l==r) return (void)(++V[now].x,V[now].y=l);
int mid=l+r>>;
if(x<=mid) modify(L[now],l,mid,x);
else modify(R[now],mid+,r,x);
V[now]=max(V[L[now]],V[R[now]]);
}
void merge(int &x,int y){
if(!x||!y) return (void)(x|=y);
if(!L[x]&&!R[x]) return (void)(V[x].x+=V[y].x);
merge(L[x],L[y]),merge(R[x],R[y]);
V[x]=max(V[L[x]],V[R[x]]);
}
data query(int p,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r) return V[p];
int mid=l+r>>;
if(qr<=mid) return query(L[p],l,mid,ql,qr);
if(ql>mid) return query(R[p],mid+,r,ql,qr);
return max(query(L[p],l,mid,ql,qr),query(R[p],mid+,r,ql,qr));
}
void dfs(int u){
for(int i=head[][u];i;i=nxt[][i])
dfs(i),merge(rt[u],rt[i]);
for(int i=head[][u];i;i=nxt[][i])
ans[i]=query(rt[u],,m,q[i].l,q[i].r);
}
int main(){
scanf("%s",s+);n=strlen(s+);
m=read();
for(int i=;i<=m;++i){
scanf("%s",t+);int len=strlen(t+);last=;
for(int j=;j<=len;++j) ins(t[j]-'a'),modify(rt[last],,m,i);
}
Q=read();
for(int i=;i<=Q;++i){
int a=read(),b=read(),c=read(),d=read();
q[i]=(node){a,b,c,d};
nxt[][i]=head[][q[i].pr],head[][q[i].pr]=i;
}
for(int i=;i<=cnt;++i)
nxt[][i]=head[][fa[][i]],head[][fa[][i]]=i;
for(int j=;j<;++j)
for(int i=;i<=cnt;++i)
fa[j][i]=fa[j-][fa[j-][i]];
for(int i=,now=,cnt=;i<=n;++i){
while(now&&!ch[now][s[i]-'a']) now=fa[][now],cnt=l[now];
if(!now){now=,cnt=;continue;}
now=ch[now][s[i]-'a'],++cnt;
for(int j=head[][i];j;j=nxt[][j]){
int u=now;if(cnt<q[j].pr-q[j].pl+) continue;
for(int k=;~k;--k)
if(l[fa[k][u]]>=q[j].pr-q[j].pl+)
u=fa[k][u];
nxt[][j]=head[][u],head[][u]=j;
}
}
dfs();
for(int i=;i<=Q;++i){
if(!ans[i].x) ans[i].y=q[i].l;
print(ans[i].y,),print(ans[i].x,);
}
Ot();
return ;
}

CF666E Forensic Examination(后缀自动机+动态线段树)的更多相关文章

  1. CF666E Forensic Examination [后缀自动机,线段树合并]

    洛谷 Codeforces 思路 最初的想法:后缀数组+区间众数,似乎并不能过. 既然后缀数组不行,那就按照套路建出广义SAM,然后把\(S\)放在上面跑,得到以每个点结尾会到SAM上哪个节点. 询问 ...

  2. CF666E Forensic Examination SAM+倍增,线段树和并

    题面: 给你一个串S以及一个字符串数组T[1..m],q次询问,每次问S的子串S[p_l..p_r]在T[l..r]中的哪个串里的出现次数最多,并输出出现次数.如有多解输出最靠前的那一个. 分析: 第 ...

  3. CF666E Forensic Examination 广义SAM、线段树合并、倍增、扫描线

    传送门 朴素想法:对\(M\)个匹配串\(T_1,...,T_M\)建立广义SAM,对于每一次询问,找到这个SAM上\(S[pl...pr]\)对应的状态,然后计算出对于每一个\(i \in [l,r ...

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

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

  5. 【BZOJ3413】匹配(后缀自动机,线段树合并)

    [BZOJ3413]匹配(后缀自动机,线段树合并) 题面 BZOJ 题解 很好的一道题目. 做一个转化,匹配的次数显然就是在可以匹配的区间中,每个前缀的出现次数之和. 首先是空前缀的出现次数,意味着你 ...

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

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

  7. CF666E Forensic Examination 广义后缀自动机_线段树合并_树上倍增

    题意: 给定一个串 $S$ 和若干个串 $T_{i}$每次询问 $S[pl..pr]$ 在 $Tl..Tr$ 中出现的最多次数,以及出现次数最多的那个串的编号. 数据范围: 需要离线 题解:首先,很常 ...

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

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

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

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

随机推荐

  1. Docker常用命令和Dockerfile语法

    Linux安装Docker: sudo wget -qO- https://get.docker.com/ | sh 安装后只能用root管理,要给其他用户权限,使用命令: sudo usermod ...

  2. Linux实战教学笔记29:MySQL数据库企业级应用实践

    第二十九节 MySQL数据库企业级应用实践 一,概述 1.1 MySQL介绍 MySQL属于传统关系型数据库产品,它开放式的架构使得用户选择性很强,同时社区开发与维护人数众多.其功能稳定,性能卓越,且 ...

  3. 如何debug?(转载)

    本文属于转载,原文地址如下: https://blog.csdn.net/zhao4zhong1/article/details/53078924 一.码畜:靠编译器帮自己查语法错误 消灭笔误:编写适 ...

  4. 手动编译cloudfoundry

    1.下载cloudfoundry源代码 git clone 2.BOSH的官方定义 BOSH是一个针对大规模分布式系统的部署和生命周期管理的开源工具,其基础是"a tool of relea ...

  5. spring4-5-事务管理

    1.简单介绍 事务管理是企业级应用程序开发中必不可少的技术,  用来确保数据的完整性和一致性. 事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用 事务的 ...

  6. UML建模之类图

    UML类间关系的种类 从一个示例开始 请看以下这个类图,类之间的关系是我们需要关注的: 车的类图结构为<<abstract>>,表示车是一个抽象类: 它有两个继承类:小汽车和自 ...

  7. [SoapUI] 通过编程的方式设置当前的Environment

    testRunner.testCase.testSuite.project.setActiveEnvironment("Live")

  8. javascrip总结42:属性操作案例: 点击盒子,改变盒子的位置和背景颜色

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...

  9. 编写高质量代码改善C#程序的157个建议——建议118:使用SecureString保存密钥等机密字符串

    建议118:使用SecureString保存密钥等机密字符串 托管代码中的字符串是一类特殊的对象,它们不可用被改变.每次使用System.String类张的方法之一时,或者使用此类型进行运算时(如赋值 ...

  10. 基于Qt5 跨平台应用开发

    1.Qt简介 2.Qt 编程关键技术 2.1 信号与槽 2.2 Qt事件处理 3.Qt开发与实例分析 3.1 开发环境 3.2 系统实现基本框架 3.3 数据库管理 3.5 对Excel进行操作 4. ...