题目:http://codeforces.com/contest/666/problem/E

对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问。

还要处理模式串的区间,可以用线段树。给广义自动机的每个节点开一棵线段树存该节点代表的串在各模式串中的出现情况。

线段树合并到叶子时,直接把出现次数相加。这样会改值,所以如果不新建节点的话,父亲用的孩子的节点,父亲又要改值,在孩子上查询的时候就错了。

  可以每次不是 ( !cr || !pr ) 的时候都新建节点。或者把询问离线挂在自动机节点上,准备把该节点的线段树合并给父亲的时候把该节点的询问先查询掉。

定位询问子串可以倍增。先走一遍得到询问串每个前缀最长匹配到哪个节点,查询子串的时候从该子串右端点对应的节点 cr 开始跳 fa 直到 len[ cr ] >= d && len[ fa ] < d (d 是询问子串长度)。跳的过程可以倍增。

注意倍增边界是 K2 而非 K 。注意数组大小 +5 。

需要判断一下询问子串没在自动机里出现。就是右端点对应的节点的匹配长度都 < d (此时没跳 fa ,是该右端点可能的最大匹配长度)。注意是 “匹配长度” 而不是该节点的 len 。

注意若没出现,返回的应是 ( L , 0 ) 。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
const int N=5e5+,M=1e5+,K=,K2=,M2=M*K2;
int n,m,Q,cnt=,fa[M],len[M],go[M][K+],pre[M][K2+],ps[N],ct[N];//K2+5!!
int c[N],tx[N],rt[M],tot,ls[M2],rs[M2];
char s[N],t[N];
struct Ques{
int l,r,id;
Ques(int l=,int r=,int i=):l(l),r(r),id(i) {}
}q[N];
struct Node{
int mx,sm;
Node(int m=,int s=):mx(m),sm(s) {}
Node operator+ (const Node &b)const
{ if(sm>=b.sm)return *this; return b;}
}vl[M2],ans[N];
vector<Ques> vt[N];
int cz(int p,int w)
{
int q=go[p][w], nq=++cnt; len[nq]=len[p]+;
fa[nq]=fa[q]; fa[q]=nq;
memcpy(go[nq],go[q],sizeof go[q]);
for(;go[p][w]==q;p=fa[p])go[p][w]=nq;
return nq;
}
int ins(int p,int w)
{
if(go[p][w])
{
int q=go[p][w];
if(len[q]==len[p]+)return q;
return cz(p,w);
}
int np=++cnt; len[np]=len[p]+;
for(;p&&!go[p][w];p=fa[p])go[p][w]=np;
if(!p){fa[np]=;return np;}
int q=go[p][w]; if(len[q]==len[p]+)fa[np]=q;
else fa[np]=cz(p,w); return np;
}
void add(int l,int r,int &cr,int p)
{
if(!cr)cr=++tot; if(l==r){vl[cr]=Node(l,); return;}
int mid=l+r>>;
if(p<=mid)add(l,mid,ls[cr],p);
else add(mid+,r,rs[cr],p);
vl[cr]=vl[ls[cr]]+vl[rs[cr]];
}
void mrg(int l,int r,int &cr,int pr)
{
if(!cr||!pr){if(!cr)cr=pr;return;}
if(l==r){vl[cr].sm+=vl[pr].sm; return;}
int mid=l+r>>;
mrg(l,mid,ls[cr],ls[pr]);
mrg(mid+,r,rs[cr],rs[pr]);
vl[cr]=vl[ls[cr]]+vl[rs[cr]];
}
Node qry(int l,int r,int cr,int L,int R)
{
if(!cr)return Node(L,);///!!
if(l>=L&&r<=R)return vl[cr];
int mid=l+r>>; Node ret=Node(L,);//L
if(L<=mid)ret=qry(l,mid,ls[cr],L,R);
if(mid<R)ret=(ret+qry(mid+,r,rs[cr],L,R));
return ret;
}
void Rsort()
{
for(int i=;i<=cnt;i++)tx[len[i]]++;
for(int i=;i<=cnt;i++)tx[i]+=tx[i-];//0 for root
for(int i=;i<=cnt;i++)c[tx[len[i]]--]=i;
}
int main()
{
scanf("%s",s+); n=strlen(s+);
m=rdn();
for(int i=;i<=m;i++)
{
scanf("%s",t+); int d=strlen(t+);
for(int j=,p=;j<=d;j++)
p=ins(p,t[j]-'a'+), add(,m,rt[p],i);
}
Rsort();
for(int i=;i<=cnt;i++)
{
int cr=c[i];
pre[cr][]=fa[cr];
for(int t=,d=fa[cr];(d=pre[d][t-]);t++)
pre[cr][t]=d;
}
Q=rdn(); int cr=;
for(int i=,c2=;i<=n;i++)
{
int w=s[i]-'a'+;
while(cr&&!go[cr][w])cr=fa[cr],c2=len[cr];
if(!go[cr][w])cr=, c2=;
else cr=go[cr][w], c2++;
ps[i]=cr;ct[i]=c2;
}
for(int i=,l,r,ql,qr;i<=Q;i++)
{
l=rdn();r=rdn();ql=rdn();qr=rdn();
int cr=ps[qr],c2=ct[qr],d=qr-ql+;
if(c2<d){ans[i]=Node(l,);continue;}//l not 1
for(int t=K2;t>=;t--)//K2!!
if(len[pre[cr][t]]>=d) cr=pre[cr][t];
vt[cr].pb(Ques(l,r,i));
}
for(int i=cnt;i>;i--)
{
int cr=c[i];
for(int j=,lm=vt[cr].size();j<lm;j++)
{
Ques q=vt[cr][j];
ans[q.id]=qry(,m,rt[cr],q.l,q.r);
}
mrg(,m,rt[fa[cr]],rt[cr]);
}
for(int i=;i<=Q;i++)printf("%d %d\n",ans[i].mx,ans[i].sm);
return ;
}

CF 666E Forensic Examination——广义后缀自动机+线段树合并的更多相关文章

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

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

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

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

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

    广义SAM专题的最后一题了……呼 题意: 给出一个长度为$n$的串$S$和$m$个串$T_{1\cdots m}$,给出$q$个询问$l,r,pl,pr$,询问$S[pl\cdots pr]$在$T_ ...

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. L252

    How often have you heard the saying, "Stop and smell the roses?" Odds are, you've come acr ...

  2. kbmMW 5.07.00试用笔记

    在kbmMW 5.06.20试用笔记中遇到的问题,在这个版本中,基本都解决了.但还是发现修正后存在的小问题及新问题: 1.Resolve返回值错误 当提交的ClientQuery是执行一条sql语句, ...

  3. ubuntu安装nodejs,npm live-server

    sudo apt-get install curl 先安装的是curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/in ...

  4. mysql字段添加修改删除

    MySQL添加字段和修改字段   MySQL添加字段的方法并不复杂,下面将为您详细介绍MYSQL添加字段和修改字段等操作的实现方法,希望对您学习MySQL添加字段方面会有所帮助. 1添加表字段 alt ...

  5. Day12作业及默写

    1.整理今天的博客,写课上代码,整理流程图. 2.用列表推导式做下列小题 li=['alex','wusir','abds','meet','ab'] a. 过滤掉长度小于3的字符串列表,并将剩下的转 ...

  6. Tomcat jdk 项目搭建问题

    Tomcat 出现log4j未找到  是因为缺少servlet包 出现版本1.5及更高错误 是Java Compiler的版本错误 需重新导包Installed JRES.

  7. js编写轮播图,广告弹框

    1.轮播图 js编写轮播图,需要用到setInterval(计时器):先给一个div,里面放轮播图的图片,将轮播图的图片明明为相同样式的:如:banner1.jpg,banner2.jpg,banne ...

  8. Python基础6--函数、类和文件操作

    1 def name(para) def myabs(x): if x>0: return x else: return -x 2 lambda表达式 用于声明匿名函数,既没有名字的小函数 f ...

  9. 使用json通过telegraf生成metrics(摘自telegraf github文档)

    JSON: The JSON data format flattens JSON into metric fields. NOTE: Only numerical values are convert ...

  10. 2017ICPC南宁赛区网络赛 Minimum Distance in a Star Graph (bfs)

    In this problem, we will define a graph called star graph, and the question is to find the minimum d ...