hdu 6138 Fleet of the Eternal Throne

来源:互联网 发布:淘宝天天疯狂购入口 编辑:程序博客网 时间:2024/05/24 07:22

后缀数组

之前一直以为把多个串连起来也是用同一个特殊字符,傻了。。这样会导致height数组的值可能包括特殊字符的长度。应该用不同的字符连接起来。此处因为可能有很多个串,所以合法数字就是0-25, 剩下的数字都是用来连接不同串的。
比较麻烦的就是查询的时候。

#include<iostream>#include<algorithm>#include<cstdlib>#include<cstdio>#include<cstring>#include<vector>#include<cmath>#include<complex>#include<queue>#define T 111111using namespace std;int s[T];int t1[T],t2[T],cc[T],x[T],sa[T],Rank[T],height[T], belong[T], is[T];int len;bool cmp(int *y,int a,int b,int k){    int a1=y[a];    int b1=y[b];    int a2=a+k>=len ? -1:y[a+k];    int b2=b+k>=len ? -1:y[b+k];    return a1==b1 && a2==b2;}void make_sa(){    int *x=t1,*y=t2;    int m=26+100000;    for(int i=0; i<m; i++) cc[i]=0;    for(int i=0; i<len; i++) ++cc[x[i]=s[i]];    for(int i=1; i<m; i++) cc[i]+=cc[i-1];    for(int i=len-1; i>=0; i--) sa[--cc[x[i]]]=i;    for(int k=1; k<=len; k<<=1)    {        int p=0;        for(int i=len-k; i<len; i++) y[p++]=i;        for(int i=0; i<len; i++)           if( sa[i]>=k ) y[p++]=sa[i]-k;        for(int i=0; i<m; i++) cc[i]=0;        for(int i=0; i<len; i++) ++cc[x[y[i]]];        for(int i=1; i<m; i++) cc[i]+=cc[i-1];        for(int i=len-1; i>=0; i--) sa[--cc[x[y[i]]]]=y[i];        swap(x,y);        m=1; x[sa[0]]=0;        for(int i=1; i<len; i++)          x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1:m++;        if( m>=len ) break;    }}void make_height(){    for(int i=0; i<len; i++) Rank[sa[i]]=i;    height[0]=0;    int k=0;    for(int i=0; i<len; i++)    {        if(!Rank[i]) continue;        int j=sa[Rank[i]-1];        if(k) k--;        while(s[i+k]==s[j+k]) k++;        height[Rank[i]]=k;    }}int main(){    char buff[100010];    int L[100010], ok;    int cas, cnt=27;    int n, m, x, y;    scanf("%d", &cas);    while(cas--)    {        scanf("%d", &n);        len=0;        memset(belong, 0, sizeof(belong));        memset(L, 0, sizeof(L));        for(int j=1; j<=n; j++)        {            scanf("%s", buff);            for(int i=len; i<len+strlen(buff); i++)            {            //is[i]==1表示这个串是符合规定的包含一个完整前缀的串                if(i==len)                    is[i]=1;                else                    is[i]=0;                s[i]=buff[i-len]-'a';       //belong[i]是指第i个字符属于第几个串,串的标号从1开始                belong[i]=j;            }            L[j]=strlen(buff);            len+=strlen(buff);            s[len++]=cnt++;        }        s[--len]='\0';        make_sa();        make_height();        scanf("%d", &m);        while(m--)        {//flagx表示x的当前值,flag表示符合规定的包含一个完整前缀的串的长度            int  flagx=0, flagy=0, flag=0, ans=0;            scanf("%d%d", &x, &y);            for(int i=0; i<len-1; i++)            {    //belong为0的值都是用来分格的数字开头的串,不用操作                if(!belong[sa[i]]) continue;                if(is[sa[i]]==1)                {        //如果找到一个符合规定的包含一个完整前缀的串                    if(belong[sa[i]]==x)                    {                         ans=max (ans, flagy);                         flagx=height[i+1];                    }                    else if(belong[sa[i]]==y)                      {                          ans=max(ans, flagx);                          flagy=height[i+1];                      }                    else                        ans=max(ans, min(flagx, flagy));                    flag=height[i+1];                }                else if(belong[sa[i]]==x)                {                    ans=max(ans, min(flagy, flag));                    flagx=height[i+1];                }                else if(belong[sa[i]]==y)                {                    ans=max(ans, min(flagx, flag));                    flagy=height[i+1];                }               //因为是取min值,每次读入一个串都要把三个值更新一下                    flag =min(flag,   height[i+1]);                    flagx=min(flagx, height[i+1]);                    flagy=min(flagy, height[i+1]);            }            printf("%d\n", ans);        }    }    return 0;}