[TJOI2013]单词

description

题面

solution

把所有字符串凑成一堆做后缀数组(中间隔开)

从高往低枚举\(LCP\)的长度\(k\),把\(Height==k\)的两个后缀使用并查集连接,
查询\(size\)即可得到以对应长度单词为前缀的后缀个数,即出现次数

code

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#define RG register
#define il inline
#define FILE "dragon"
using namespace std;
typedef long long ll;
typedef double dd;
const int N=2000010;
const int inf=2147483647;
const ll INF=1e18+1;
il void file(){
    freopen(FILE".in","r",stdin);
    freopen(FILE".out","w",stdout);
}
il ll read(){
    RG ll d=0,w=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch<='9'&&ch>='0')d=d*10+ch-48,ch=getchar();	
    return d*w;
}

char s[N];
int n,len;
int sa[N],rk[N],t[N],x[N],y[N],m,height[N];
il bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];}
il void getsa(){
    m=30;
    for(RG int i=1;i<=n;i++)t[x[i]=(s[i]-'a'+1)]++;
    for(RG int i=1;i<=m;i++)t[i]+=t[i-1];
    for(RG int i=n;i;i--)sa[t[x[i]]--]=i;
    for(RG int k=1,p;k<=n;k<<=1){
        p=0;
        for(RG int i=0;i<=m;i++)t[i]=y[i]=0;
        for(RG int i=n-k+1;i<=n;i++)y[++p]=i;
        for(RG int i=1;i<=n;i++)if(sa[i]>k)y[++p]=sa[i]-k;
        for(RG int i=1;i<=n;i++)t[x[y[i]]]++;
        for(RG int i=1;i<=m;i++)t[i]+=t[i-1];
        for(RG int i=n;i;i--)sa[t[x[y[i]]]--]=y[i];
        swap(x,y);x[sa[1]]=p=1;
        for(RG int i=2;i<=n;i++)x[sa[i]]=cmp(sa[i],sa[i-1],k)?p:++p;
        if(p>=n)break;m=p;
    }
    for(RG int i=1;i<=n;i++)rk[sa[i]]=i;
    for(RG int i=1;i<=n;i++){
        height[rk[i]]=height[rk[i-1]]?height[rk[i-1]]-1:0;
        while(s[sa[rk[i]-1]+height[rk[i]]]==s[i+height[rk[i]]])
            height[rk[i]]++;
    }
}

struct node{int a,b,id;}o[N],S[N];
bool cmp_a(node x,node y){return x.a==y.a?x.b>y.b:x.a>y.a;}
bool cmp_b(node x,node y){return x.b==y.b?x.a>y.a:x.b>y.b;}

int ans[N],fa[N],sz[N];
il int find(int x){return fa[x]?fa[x]=find(fa[x]):x;}
il void Union(int x,int y){
    x=find(x);y=find(y);if(x==y)return;
    fa[x]=y;sz[y]+=sz[x];
}
il int getsz(int x){return sz[find(x)];}

int main()
{
    n=read();len=0;
    for(RG int i=1;i<=n;i++){
        S[i].id=i;
        S[i].b=len+1;
        scanf("%s",s+len+1);
        S[i].a=strlen(s+len+1);
        len=strlen(s+1);
        if(i!=n)s[++len]='z'+1;
    }
    sort(S+1,S+n+1,cmp_a);
    
    swap(n,len);
    getsa();
    for(RG int i=1;i<=n;i++)sz[i]=1;
    for(RG int i=1;i<=n;i++)o[i]=(node){height[i],i,i};
    sort(o+1,o+n+1,cmp_a);
    for(RG int i=1,p=0;i<=len;i++){
        while(o[p+1].a>=S[i].a){p++;Union(sa[o[p].b],sa[o[p].b-1]);}
        ans[S[i].id]=getsz(S[i].b);
    }
    for(RG int i=1;i<=len;i++)printf("%d\n",ans[i]);
    return 0;
}
posted @ 2018-07-23 11:18  cjfdf  阅读(176)  评论(0编辑  收藏  举报