zoukankan      html  css  js  c++  java
  • [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
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    关于《大道至简-软件工程实践者的思想》的读书笔记(二)
    关于《大道至简-软件工程实践者的思想》的读书笔记(一)
    Android源码项目目录结构
    Android源码目录结构详解
    项目阶段总结
    站立会议07(二期)
    站立会议06(二期)
    站立会议05(二期)
    站立会议04(二期)
    站立会议03(二期)
  • 原文地址:https://www.cnblogs.com/cjfdf/p/9353695.html
Copyright © 2011-2022 走看看