bzoj3413 匹配

题目描述

题解:

最开始我想倒建倒查,结果发现需要另开线段树维护,结果算法退化了……

说正解。

正建正查。

线段树合并+SAM。

将询问串放在SAM中,判断是否有匹配。

然后设定边界就可以了。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100050
#define ll long long
const int inf = 0x3f3f3f3f;
char s[N];
int n,m,len;
struct node
{
    int len,pre,trs[12];
}p[2*N];
int hed[2*N],cnt;
ll ans = 0;
struct segtree
{
    int tot,siz[80*N],ls[80*N],rs[80*N],rt[2*N];
    void insert(int &u,int l,int r,int qx)
    {
        u = ++tot;
        siz[u]++;
        if(l==r)return ;
        int mid = (l+r)>>1;
        if(qx<=mid)insert(ls[u],l,mid,qx);
        else insert(rs[u],mid+1,r,qx);
    }
    int merge(int l,int r)
    {
        if(!l||!r)return l+r;
        int u = ++tot;
        siz[u] = siz[l]+siz[r];
        ls[u] = merge(ls[l],ls[r]);
        rs[u] = merge(rs[l],rs[r]);
        return u;
    }
    int query(int u,int l,int r,int ql,int qr)
    {
        if(!u)return 0;
        if(l==ql&&r==qr)return siz[u];
        int mid = (l+r)>>1;
        if(qr<=mid)return query(ls[u],l,mid,ql,qr);
        else if(ql>mid)return query(rs[u],mid+1,r,ql,qr);
        else return query(ls[u],l,mid,ql,mid)+query(rs[u],mid+1,r,mid+1,qr);
    }
    int min_pos(int u,int l,int r)
    {
        if(l==r)return l;
        int mid = (l+r)>>1;
        if(siz[ls[u]])return min_pos(ls[u],l,mid);
        else return min_pos(rs[u],mid+1,r);
    }
}tr;
struct SAM
{
    int las,tot;
    SAM(){las=tot=1;}
    void insert(int c,int k)
    {
        int np,nq,lp,lq;
        np=++tot;
        p[np].len = p[las].len+1;
        tr.insert(tr.rt[np],1,n,k);
        for(lp=las;lp&&!p[lp].trs[c];lp=p[lp].pre)
            p[lp].trs[c]=np;
        if(!lp)p[np].pre = 1;
        else
        {
            lq = p[lp].trs[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[lq].pre = p[np].pre = nq;
                while(p[lp].trs[c]==lq)
                {
                    p[lp].trs[c]=nq;
                    lp=p[lp].pre;
                }
            }
        }
        las = np;
    }
    int hs[2*N],topo[2*N];
    void build()
    {
        for(int i=1;i<=tot;i++)hs[p[i].len]++;
        for(int i=1;i<=tot;i++)hs[i]+=hs[i-1];
        for(int i=1;i<=tot;i++)topo[hs[p[i].len]--]=i;
        for(int i=tot;i>=1;i--)
        {
            int x = topo[i];
            tr.rt[p[x].pre]=tr.merge(tr.rt[p[x].pre],tr.rt[x]);
        }
    }
}sam;
int main()
{
    scanf("%d%s",&n,s+1);
    for(int i=1;i<=n;i++)
        sam.insert(s[i]-'0',i);
    sam.build();
    scanf("%d",&m);
    while(m--)
    {
        scanf("%s",s+1);
        len = strlen(s+1);
        ans = 0;
        int endpos = inf,u = 1;
        for(int i=1;i<=len;i++)
            u = p[u].trs[s[i]-'0'];
        if(!u)ans = n;
        else
        {
            endpos = tr.min_pos(tr.rt[u],1,n);
            ans = endpos - len;
        }
        u = 1;
        for(int i=1;i<=len;i++)
        {
            u = p[u].trs[s[i]-'0'];
            if(!u)break;
            int qr = min(n,endpos-len+i);
            ans+=tr.query(tr.rt[u],1,n,1,qr);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2018-12-15 10:13  LiGuanlin  阅读(212)  评论(0编辑  收藏  举报