Codeforces 666E Forensic Examination

题意:给定主串s和m个模式串,每次询问[l,r]的模式串中出现s[pl...pr]次数最多的串和次数。

这题挺简单的,先把所有模式串拿来建广义后缀自动机,询问相当于子树众数,用线段树合并即可。

那我为什么写这题题解呢?

1.作为我博客第一道非BZOJ题。

2.作为我博客第一道写题意(英文)的题。

3.这题是老师留的作业,所以可以骗访问量。

4.记录一下广义后缀自动机的优秀写法,以前我是无脑建的。

#include <cstdio>
#include <algorithm>
using namespace std;
#define l(x) t[x].l
#define r(x) t[x].r
#define M ((L+R)>>1)

typedef pair<int,int> pr;
const int S=500005,N=100005;
char s[N],sr[S];
int m,e,q,l1,r1,l2,r2,ls,sz,tt,po[S],ln[S],l[N],f[N],ch[N][26],hd[N],nx[N],to[N],rt[N],fa[N][21];
struct nd {int l,r; pr p;}t[N*30];
void ad(int x,int y) {to[++e]=y,nx[e]=hd[x],hd[x]=e;}

void ins(int c) {
    int u=ls,x=ch[u][c];
    if(x) {
        if(l[u]+1==l[x]) {ls=x; return;}
        l[++sz]=l[u]+1,f[sz]=f[x],f[x]=sz,ls=sz;
        for(int j=0;j<26;j++) ch[sz][j]=ch[x][j];
        for(;u&&ch[u][c]==x;u=f[u]) ch[u][c]=sz;
        if(ch[u][c]==x) ch[u][c]=sz;
    } else {
        for(ls=++sz,l[sz]=l[u]+1;u&&!ch[u][c];u=f[u]) ch[u][c]=sz;
        int x=ch[u][c];
        if(!x) {ch[u][c]=sz; return;}
        if(l[u]+1==l[x]) {f[sz]=x; return;}
        l[++sz]=l[u]+1,f[sz]=f[x],f[x]=f[ls]=sz;
        for(int j=0;j<26;j++) ch[sz][j]=ch[x][j];
        for(;u&&ch[u][c]==x;u=f[u]) ch[u][c]=sz;
        if(ch[u][c]==x) ch[u][c]=sz;
    }
}

void pu(int x) {t[x].p=max(t[l(x)].p,t[r(x)].p);}
int mrg(int x,int y,int L=1,int R=m) {
    if(!x||!y) return x|y;
    int z=++tt;
    if(L==R) {t[z].p=make_pair(t[x].p.first+t[y].p.first,-L); return z;}
    l(z)=mrg(l(x),l(y),L,M),r(z)=mrg(r(x),r(y),M+1,R),pu(z);
    return z;
}
void upd(int &x,int v,int L=1,int R=m) {
    if(!x) x=++tt;
    if(L==R) {t[x].p=make_pair(t[x].p.first+1,-v); return;}
    if(v<=M) upd(l(x),v,L,M); else upd(r(x),v,M+1,R);
    pu(x);
}
pr qr(int x,int l,int r,int L=1,int R=m) {
    if(!x) return make_pair(0,0);
    if(l<=L&&r>=R) return t[x].p;
    if(r<=M) return qr(l(x),l,r,L,M); if(l>M) return qr(r(x),l,r,M+1,R);
    return max(qr(l(x),l,r,L,M),qr(r(x),l,r,M+1,R));
}

int gt(int x,int ln) {for(int i=20;~i;i--) if(l[fa[x][i]]>=ln) x=fa[x][i]; return x;}
void dfs(int x) {for(int i=hd[x];i;i=nx[i]) dfs(to[i]),rt[x]=mrg(rt[x],rt[to[i]]),fa[to[i]][0]=x;}

int main() {
    scanf("%s%d",sr,&m);
    for(int i=1;i<=m;i++) {
        scanf("%s",s),ls=0;
        for(int j=0;s[j];j++) ins(s[j]-'a'),upd(rt[ls],i);
    }
    for(int i=0,u=0,s=0;sr[i];i++) {
        int c=sr[i]-'a';
        while(u&&!ch[u][c]) u=f[u],s=l[u];
        if(ch[u][c]) ln[i+1]=++s,u=ch[u][c],po[i+1]=u;
    }
    for(int i=1;i<=sz;i++) ad(f[i],i);
    dfs(0),scanf("%d",&q);
    for(int j=1;j<21;j++) for(int i=1;i<=sz;i++) fa[i][j]=fa[fa[i][j-1]][j-1];
    while(q--) {
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        if(ln[r2]<r2-l2+1) {printf("%d 0\n",l1); continue;}
        pr k=qr(rt[gt(po[r2],r2-l2+1)],l1,r1);
        if(k.first) printf("%d %d\n",-k.second,k.first); else printf("%d 0\n",l1);
    }
    return 0;
}
posted @ 2017-06-21 19:53  Monster_Yi  阅读(425)  评论(0编辑  收藏  举报