P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队)

Posted kafuuchino

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队)相关的知识,希望对你有一定的参考价值。

P2336 [SCOI2012]喵星球上的点名

 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define rint register int
using namespace std;
int read(){
    char c=getchar();int x=0;
    while(c<0||c>9) c=getchar();
    while(0<=c&&c<=9) x=x*10+(c^48),c=getchar();
    return x;
}
#define N 200005
int n,m,Len,L,R,dfn[N],siz[N],Co[N];
int tt,in[N],Ls[N],ans1[N],ans2[N],tot;
int cnt,hd[N],nxt[N],ed[N],poi[N];
struct data{int l,r,Id;}a[N];
inline bool cmp(data A,data B){
    return (A.l/Len==B.l/Len)?A.r<B.r:A.l/Len<B.l/Len;
}
inline void adde(int x,int y){
    nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt,
    ed[x]=cnt, poi[cnt]=y;
}
struct Sam{
    int fa[N],len[N],col[N],ed,q,Clock;
    Sam(){Clock=0;ed=1;}
    map<int,int> mp[N];
    int add(int p,int x,int id){
        len[++ed]=len[p]+1; col[ed]=id;
        for(;p&&!mp[p][x];p=fa[p]) mp[p][x]=ed;
        if(!p) {fa[ed]=1;return ed;}
        q=mp[p][x];
        if(len[q]==len[p]+1){fa[ed]=q;return ed;}
        len[++ed]=len[p]+1; mp[ed]=mp[q];
        fa[ed]=fa[q]; fa[q]=fa[ed-1]=ed;
        for(;mp[p][x]==q;p=fa[p]) mp[p][x]=ed;
        return ed-1;
    }
    void link(){for(rint i=1;i<=ed;++i) adde(fa[i],i);}
    void dfs(int x){//dfs把parent树映射到序列上
        dfn[x]=++Clock; Co[Clock]=col[x]; siz[x]=1;
        for(int i=hd[x];i;i=nxt[i])
            dfs(poi[i]),siz[x]+=siz[poi[i]];
    }
}S;
int main(){
    n=read();m=read();int q,now;
    for(rint i=1;i<=n;++i){
        q=read(); now=1;
        while(q--) now=S.add(now,read(),i);
        q=read(); now=1;
        while(q--) now=S.add(now,read(),i);
    }S.link(); S.dfs(1); Len=sqrt(S.ed);
    for(rint i=1;i<=m;++i){
        q=read();now=1;
        while(q--) now=S.mp[now][read()];
        if(!now) continue;
        a[++tt]=(data){dfn[now],dfn[now]+siz[now]-1,i};
    }
    if(tt){//在映射序列上进行莫队
        sort(a+1,a+tt+1,cmp);
        for(rint i=a[1].l;i<=a[1].r;++i){
            if(!in[Co[i]]&&Co[i]) ++tot,Ls[Co[i]]=1;
            ++in[Co[i]];
        }ans1[a[1].Id]=tot; L=a[1].l; R=a[1].r;
        for(rint i=2;i<=tt;++i){
            while(L<a[i].l){
                --in[Co[L]];
                if(!in[Co[L]]&&Co[L]) --tot,ans2[Co[L]]+=i-Ls[Co[L]];
                ++L;
            }
            while(R>a[i].r){
                --in[Co[R]];
                if(!in[Co[R]]&&Co[R]) --tot,ans2[Co[R]]+=i-Ls[Co[R]];
                --R;
            }
            while(L>a[i].l){
                --L;
                if(!in[Co[L]]&&Co[L]) ++tot,Ls[Co[L]]=i;
                ++in[Co[L]];
            }
            while(R<a[i].r){
                ++R;
                if(!in[Co[R]]&&Co[R]) ++tot,Ls[Co[R]]=i;
                ++in[Co[R]];
            }
            ans1[a[i].Id]=tot;
        }
        while(L<=R){
            --in[Co[L]];
            if(!in[Co[L]]&&Co[L]) --tot,ans2[Co[L]]+=tt-Ls[Co[L]]+1;
            ++L;
        }//注意最后剩下的数据要算进去
    }
    for(rint i=1;i<=m;++i) printf("%d
",ans1[i]);
    for(rint i=1;i<=n;++i) printf("%d ",ans2[i]);
    return 0;
}

 

以上是关于P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队)的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P2336 [SCOI2012]喵星球上的点名(SA+莫队)

luogu P2336 [SCOI2012]喵星球上的点名

bzoj2754SCOI2012喵星球上的点名

BZOJ 2754: [SCOI2012]喵星球上的点名

bzoj2754 [SCOI2012]喵星球上的点名 (后缀数组+树状数组)

BZOJ 2754: [SCOI2012]喵星球上的点名