广义SAM专题的最后一题了……呼

题意:

给出一个长度为$n$的串$S$和$m$个串$T_{1\cdots m}$,给出$q$个询问$l,r,pl,pr$,询问$S[pl\cdots pr]$在$T_l\cdots T_r$中哪个串出现次数最多,出现了多少次。

$1\leq n,q\leq 10^5,1\leq m,\sum|T|\leq 10^4$

串中只会出现小写字母

题解:

神题啊……放图镇楼

先对T串建出广义SAM,然后把S放到上面匹配,求出每个字符所代表的节点,那么每次查询就相当于求这一段字符在SAM上对应的节点的right集合包含的字符串的众数是哪个串,显然这是parent树上的一个子树众数问题;

考虑如何维护right集合在所有$T$中的出现次数,可以对每一个节点开一棵线段树,维护每个T串的出现次数的最大值,这样子在parent树上从下往上线段树合并即可求出right集合;

把询问离线按照右端点排序,把询问标记打在parent树上,最后dfs一遍合并+处理询问即可;

口胡起来不难但是写起来……超爽!

代码:

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#define inf 2147483647
#define eps 1e-9
using namespace std;
typedef long long ll;
typedef double db;
struct task{
int v,id;
task(){v=id=;}
friend bool operator <(task a,task b){
return a.v==b.v?a.id>b.id:a.v<b.v;
}
}ans[];
struct qu{
int l,r,ql,qr;
}q[];
struct edge{
int v,next;
}a[];
struct node{
int ls,rs;
task v;
}t[];
int n,m,Q,len,ch,nw=,tote=,tot=,rt=,cnt=,last,head[],rts[],son[][],fa[],mx[],f[][];
vector<int>qrs[];
vector<int>as[];
char st[],tt[];
void add(int u,int v){
a[++tote].v=v;
a[tote].next=head[u];
head[u]=tote;
}
void updata(int &u,int l,int r,int x){
if(!u)u=++cnt;
if(l==r){
t[u].v.v++;
t[u].v.id=x;
return;
}
int mid=(l+r)/;
if(x<=mid)updata(t[u].ls,l,mid,x);
else updata(t[u].rs,mid+,r,x);
t[u].v=max(t[t[u].ls].v,t[t[u].rs].v);
}
void merge(int &x,int y){
if(!x||!y){
x|=y;
return;
}
if(!t[x].ls&&!t[x].rs){
t[x].v.v+=t[y].v.v;
return;
}
merge(t[x].ls,t[y].ls);
merge(t[x].rs,t[y].rs);
t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
}
task query(int u,int l,int r,int L,int R){
if(L<=l&&r<=R){
return t[u].v;
}
int mid=(l+r)/;
task ret;
if(L<=mid)ret=max(ret,query(t[u].ls,l,mid,L,R));
if(mid<R)ret=max(ret,query(t[u].rs,mid+,r,L,R));
return ret;
}
void extend(int ch){
int p=last,np=++tot;
mx[np]=mx[p]+;
for(;p&&!son[p][ch];p=fa[p])son[p][ch]=np;
if(!p)fa[np]=rt;
else{
int q=son[p][ch];
if(mx[q]==mx[p]+)fa[np]=q;
else{
int nq=++tot;
mx[nq]=mx[p]+;
memcpy(son[nq],son[q],sizeof(son[q]));
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for(;p&&son[p][ch]==q;p=fa[p])son[p][ch]=nq;
}
}
last=np;
}
void dfs(int u){
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
dfs(v);
merge(rts[u],rts[v]);
}
for(int i=,ii=as[u].size();i<ii;i++){
ans[as[u][i]]=query(rts[u],,m,q[as[u][i]].l,q[as[u][i]].r);
}
}
int main(){
memset(head,-,sizeof(head));
scanf("%s%d",st+,&m);
n=strlen(st+);
for(int i=;i<=m;i++){
scanf("%s",tt);
len=strlen(tt);
last=rt;
for(int j=;j<len;j++){
extend(tt[j]-'a');
updata(rts[last],,m,i);
}
}
scanf("%d",&Q);
for(int i=;i<=Q;i++){
scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].ql,&q[i].qr);
qrs[q[i].qr].push_back(i);
}
for(int i=;i<=tot;i++){
f[i][]=fa[i];
add(fa[i],i);
}
for(int j=;j<=;j++){
for(int i=;i<=tot;i++){
f[i][j]=f[f[i][j-]][j-];
}
}
len=;
for(int i=;i<=n;i++){
ch=st[i]-'a';
for(;nw&&!son[nw][ch];)nw=fa[nw],len=mx[nw];
if(!nw){
nw=rt;
len=;
}else{
nw=son[nw][ch];
len++;
for(int j=,jj=qrs[i].size();j<jj;j++){
int v=qrs[i][j];
if(len>=q[v].qr-q[v].ql+){
int _nw=nw;
for(int k=;k>=;k--){
if(mx[f[_nw][k]]>=q[v].qr-q[v].ql+){
_nw=f[_nw][k];
}
}
as[_nw].push_back(v);
}
}
}
}
dfs();
for(int i=;i<=Q;i++){
if(!ans[i].v)ans[i].id=q[i].l;
printf("%d %d\n",ans[i].id,ans[i].v);
}
return ;
}

【CF666E】Forensic Examination - 广义后缀自动机+线段树合并的更多相关文章

  1. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  2. CF 666E Forensic Examination——广义后缀自动机+线段树合并

    题目:http://codeforces.com/contest/666/problem/E 对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问. 还要处 ...

  3. [CF666E]Forensic Examination:后缀自动机+线段树合并

    分析 用到了两个小套路: 使用线段树合并维护广义后缀自动机的\(right\)集合. 查询\(S[L,R]\)在\(T\)中的出现次数:给\(T\)建SAM,在上面跑\(S\),跑到\(R\)的时候先 ...

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

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

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

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

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

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

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

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

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

    将所有串(包括S)放一块建SAM.对于询问,倍增定位出该子串所在节点,然后要查询的就是该子串在区间内的哪个字符串出现最多.可以线段树合并求出该节点在每个字符串中的出现次数. #include<b ...

  9. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...

随机推荐

  1. dubbo-源码阅读之javaspi&javasist简单使用

    dubbo可扩展的点的类的对象创建 都是用类似javaspi和javasist的思想来做的.所以看后面代码 先熟悉一下java的SPI和javasist的使用 如ServicesConfig的代码 p ...

  2. 修改oracle客户端的字符集

    客户端字符集环境select * from nls_instance_parameters,其来源于v$parameter, 表示客户端的字符集的设置,可能是参数文件,环境变量或者是注册表 方法有 : ...

  3. 一个表空间使用率查询sql的优化

    话不多说,直接上运行计划: SQL> set lines 500; SQL> set pagesize 9999; SQL> set long 9999; SQL> selec ...

  4. [Javascript Crocks] Understand the Maybe Data Type

    In this lesson, we’ll get started with the Maybe type. We’ll look at the underlying Just and Nothing ...

  5. android 细节之An internal error occurred during: &quot;Launching New_configuration&quot;.

    今天在导入公司的一个小demo时候发现了一个非常有意思的错误. An internal error occurred during: "Launching New_configuration ...

  6. 公布IOS产品被拒后怎样再上传新公布包

    问题描写叙述: 前两天提交公司产品2.0.7版本号到苹果审核,昨天提示被拒绝. 被拒原因就不描写叙述了. 我们经过改动后.又一次打包上传,但是怎么也提交不了.由于在苹果后台上已经存在2.0.7版本号的 ...

  7. C语言开发函数库时利用不透明指针对外隐藏结构体细节

    1 模块化设计要求库接口隐藏实现细节 作为一个函数库来说,尽力降低和其调用方的耦合.是最主要的设计标准. C语言,作为经典"程序=数据结构+算法"的践行者,在实现函数库的时候,必定 ...

  8. URAL 1826. Minefield(数学 递归)

    题目链接:http://acm.timus.ru/problem.aspx? space=1&num=1826 1826. Minefield Time limit: 0.5 second M ...

  9. bzoj5178: [Jsoi2011]棒棒糖

    就是裸的主席树嘛... 表扬一下自己1A #include<cstdio> #include<iostream> #include<cstring> #includ ...

  10. Code Coverage and Unit Test in SonarQube

    概念 https://blog.ndepend.com/guide-code-coverage-tools/ Code Coverage Results Import (C#, VB.NET) Uni ...