CF666E Forensic Examination

题目描述

题解:

广义$SAM$+倍增+线段树合并三连。

对于给出的$m$个串建广义后缀自动机,用线段树合并处理$parent$树子树内所有串出现次数。

将询问挂在第$pr$位上。

最后扫一遍原串,记录当前节点以及当前串长,在$parent$树上倍增找$s[pl,pr]$串,最后用线段树查询就好了。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 500050;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
char s[N],s0[N];
int m,rt[N<<1],q,a1[N],a2[N];
struct segtree
{
    int tot,ls[N<<4],rs[N<<4],siz[N<<4],nam[N<<4];
    void update(int u)
    {
        if(siz[ls[u]]<siz[rs[u]])
        {
            nam[u] = nam[rs[u]];
            siz[u] = siz[rs[u]];
        }else
        {
            nam[u] = nam[ls[u]];
            siz[u] = siz[ls[u]];
        }
    }
    void insert(int l,int r,int &u,int qx)
    {
        if(!u)u=++tot;
        if(l==r)
        {
            nam[u] = l;
            siz[u]++;
            return ;
        }
        int mid = (l+r)>>1;
        if(qx<=mid)insert(l,mid,ls[u],qx);
        else insert(mid+1,r,rs[u],qx);
        update(u);
    }
    int merge(int l,int r,int x,int y)
    {
        if(!x||!y)return x+y;
        int z = ++tot,mid = (l+r)>>1;
        if(l==r)siz[z] = siz[x]+siz[y],nam[z] = l;
        else
        {
            ls[z] = merge(l,mid,ls[x],ls[y]);
            rs[z] = merge(mid+1,r,rs[x],rs[y]);
            update(z);
        }
        return z;
    }
    void query(int l,int r,int u,int ql,int qr,int&h1,int&h2)
    {
        if(!u)return ;
        if(l==ql&&r==qr)
        {
            if(h2<siz[u])
            {
                h1 = nam[u];
                h2 = siz[u];
            }
            return ;
        }
        int mid = (l+r)>>1;
        if(qr<=mid)query(l,mid,ls[u],ql,qr,h1,h2);
        else if(ql>mid)query(mid+1,r,rs[u],ql,qr,h1,h2);
        else query(l,mid,ls[u],ql,mid,h1,h2),query(mid+1,r,rs[u],mid+1,qr,h1,h2);
    }
}tr;
int f[N<<1][22];
struct Pnt
{
    int ch[26],len,pre;
}p[N<<1];
struct SAM
{
    int tot,las;
    SAM(){tot=las=1;}
    void init(){las=1;}
    void insert(int c,int i)
    {
        if(p[las].ch[c])
        {
            int lp = las,lq = p[lp].ch[c];
            if(p[lq].len==p[lp].len+1)
            {
                las = lq;
                tr.insert(1,m,rt[lq],i);
            }else
            {
                int nq = ++tot;
                p[nq] = p[lq];
                p[nq].len = p[lp].len+1;
                p[lq].pre = nq;
                for(;p[lp].ch[c]==lq;lp=p[lp].pre)
                {
                    p[lp].ch[c] = nq;
                }
                tr.insert(1,m,rt[nq],i);
                las = nq;
            }
            return ;
        }
        int np,nq,lp,lq;
        np = ++tot;
        p[np].len = p[las].len+1;
        tr.insert(1,m,rt[np],i);
        for(lp=las;lp&&!p[lp].ch[c];lp=p[lp].pre)
            p[lp].ch[c]=np;
        if(!lp)p[np].pre = 1;
        else
        {
            lq = p[lp].ch[c];
            if(p[lq].len==p[lp].len+1)p[np].pre = lq;
            else
            {
                nq = ++tot;
                p[nq] = p[lq];
                p[nq].len = p[lp].len+1;
                p[np].pre = p[lq].pre = nq;
                for(;p[lp].ch[c]==lq;lp=p[lp].pre)
                    p[lp].ch[c]=nq;
            }
        }
        las = np;
    }
    int hs[N<<1],sta[N<<1];
    void build()
    {
        for(int i=1;i<=tot;i++)hs[p[i].len]++,f[i][0]=p[i].pre;
        for(int i=1;i<=tot;i++)hs[i]+=hs[i-1];
        for(int i=1;i<=tot;i++)sta[hs[p[i].len]--]=i;
        for(int i=tot;i>=1;i--)
            rt[p[sta[i]].pre]=tr.merge(1,m,rt[p[sta[i]].pre],rt[sta[i]]);
        for(int k=1;k<=20;k++)
            for(int i=1;i<=tot;i++)
                f[i][k]=f[f[i][k-1]][k-1];
    }
}sam;
int hed[N],cnt;
struct EG
{
    int l,r,pl,id,nxt;
}e[N];
void ae(int f,int l,int r,int i,int pl)
{
    e[++cnt].l = l;
    e[cnt].r = r;
    e[cnt].id = i;
    e[cnt].pl = pl;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
int main()
{
//    freopen("tt.in","r",stdin);
    scanf("%s",s+1);
    read(m);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",s0+1);
        int len = strlen(s0+1);
        sam.init();
        for(int j=1;j<=len;j++)
        {
            int c = s0[j]-'a';
            sam.insert(c,i);
        }
    }
    sam.build();
    read(q);
    for(int l,r,pl,pr,i=1;i<=q;i++)
    {
        read(l),read(r),read(pl),read(pr);
        ae(pr,l,r,i,pl);
    }
    int u = 1;
    for(int i=1,lim=strlen(s+1),len=0;i<=lim;i++)
    {
        while(u&&!p[u].ch[s[i]-'a'])u=p[u].pre,len=p[u].len;
        if(!u)u=1,len=0;
        else u=p[u].ch[s[i]-'a'],len++;
        for(int j=hed[i];j;j=e[j].nxt)
        {
            int now = u;
            int ln = i-e[j].pl+1;
            if(len<ln)
            {
                a1[e[j].id] = e[j].l;
                continue;
            }
            for(int k=20;k>=0;k--)
                if(p[f[now][k]].len>=ln)now=f[now][k];
            tr.query(1,m,rt[now],e[j].l,e[j].r,a1[e[j].id]=e[j].l,a2[e[j].id]);
        }
    }
    for(int i=1;i<=q;i++)
        printf("%d %d\n",a1[i],a2[i]);
    return 0;
}
View Code

 

posted @ 2019-04-19 16:44  LiGuanlin  阅读(161)  评论(0编辑  收藏  举报