广义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. mysql 的load data infile

    LOAD DATA INFILE语句从一个文本文件中以很高的速度读入一个表中.如果指定LOCAL关键词,从客户主机读文件.如果LOCAL没指定,文件必须位于服务器上.(LOCAL在MySQL3.22. ...

  2. Efficient ticket lock synchronization implementation using early wakeup in the presence of oversubscription

    A turn-oriented thread and/or process synchronization facility obtains a ticket value from a monoton ...

  3. 【ACM】hdu_1093_A+BV_201307261715

    A+B for Input-Output Practice (V)Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 ...

  4. Marching squares &amp; Marching cubes

    提要 Marching squares 主要是用于从一个地图(用二维数组表示)生成轮廓的算法.Marching cubes则相应的是在空间生成网格的方法.最常见的应用就是天气预报中气压图的生成.还经常 ...

  5. 如何构建一个轻量级级的DI(依赖注入)

    概念:依赖注入与IOC模式类似工厂模式,是一种解决调用者和被调用者依赖耦合关系的模式:它解决了对象之间的依赖关系,使得对象只依赖IOC/DI容器,不再直接相互依赖,实现松耦合,然后在对象创建时,由IO ...

  6. LeetCode(1) Symmetric Tree

    从简单的道题目開始刷题目: Symmetric Tree 题目:Given a binary tree, check whether it is a mirror of itself (ie, sym ...

  7. 【待解决】创建maven web工程报错

    报错信息如下: Could not calculate build plan: Plugin org.apache.maven.plugins:maven-resources-plugin:2.6 o ...

  8. Memcache 和 Radis 比较

    Memcache 和 Radis 比较 2014-03-28 11:00 2447人阅读 评论(0) 收藏 举报  分类: memcache(6)  Redis(7)  版权声明:本文为博主原创文章, ...

  9. luogu2431 正妹吃月饼

    题目大意 求一个正整数集合\(K\),使得\(\sum_{k\in K}2^k\in[A,B]\),且\(|K|\)最大.\(A,B\)大小在long long范围内. 思路 \(\sum_{k\in ...

  10. Mail发送封装类

    代码实现: MailSmtp ms = ","xxxx"); //可选参数 ms.SetCC("610262374@qq.com");//抄送可以多个 ...