题意

  给你一个串 $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. Hibernate一对多操作

    --------------------siwuxie095 Hibernate 一对多操作 以客户和联系人为例,客户是一,联系人是多 即 一个客户里面有多个联系人,一个联系人只能属于一个客户 注意: ...

  2. android-tip-SocketException之ETIMEDOUT

    异常出现时间 如果我们有一个长连接,此时网络被关闭,或者暂时失去信号, 此时就会出现此异常. 如果出现此异常,则不得不重连.

  3. adf错误

    1>无法验证事务处理中的所有行 运行项目报错: javax.faces.el.EvaluationException: oracle.jbo.TxnValException: JBO-27023 ...

  4. SqlSugar Asp.Net 高性能ORM框架

    SqlSugar从去年到现在已经一年了,版本从1.0升到了现在的2.4.1 ,这是一个稳定版本 ,有数家公司已经项目上线,在这里我将SqlSugar的功能重新整理成一篇新的贴子,希望大家喜欢. 公司团 ...

  5. 最大公约数(gcd)和 最小公倍数(lcm)——辗转相除法

    辗转相除法(又称欧几里得算法)是求最大公因数的算法 要求a,b的最大公约数(a>b),我们可以递归地求b,a%b的最大公约数,直到其中一个数变成0,这时另一个数就是a,b的最大公约数. C++实 ...

  6. Debian/Linux系统安全配置教程

    禁止root SSH登陆 配置SSH Key 配置iptables 当我们安装完Linux系统作为服务器后,总有一系列的安全配置需要进行.特别是当你的服务器Ip是对外网开放的话.全世界有很多不怀好意的 ...

  7. 1517 u Calculate e

    1. 最前面的格式要记得输入. 2. 计算的时候要从3开始重新计算, 否则会丢失精度. 3. 更快的方式就是打表. #include <iostream> using namespace ...

  8. Tomcat 开机自启动

    一.安装JDK和Tomcat 1,安装JDK:直接运行jdk-7-windows-i586.exe可执行程序,默认安装即可. 备注:路径可以其他盘符,不建议路径包含中文名及特殊符号. 2.安装Tomc ...

  9. jmeter监控内存,CPU等方法

    方法1: 使用插件来监控CPU,内存等的使用情况 1.需要的插件准备 JMeterPlugins-Standard-1.4.0.zip , JMeterPlugins-Extras-1.4.0.zip ...

  10. 卸载超级兔子后,word打不开(无法创建工作文件),VS2010也没法用(找不到CL.exe)。

    又折腾了一上午,昨天用优化大师和超级兔子整理了电脑,今天来到实验室,vs打开后报错,提示"找不到CL.exe,"(具体提示忘记了,就是找不到CL.exe),打开word2010也是 ...