poj 2758 Checking the Text (后缀数组应用)

来源:互联网 发布:淘宝网实名认证在哪里 编辑:程序博客网 时间:2024/05/20 06:28

题意:

给出一个串,对这个串进行插入,查询,查询是按照原来串的位置进行查询a,b为开头的后缀的最长公共前缀。

题解:

的确是一道好题。参考大牛博客


#include<iostream>#include<math.h>#include<stdio.h>#include<algorithm>#include<string.h>#include<vector>#include<queue>#include<map>#include<set>using namespace std;#define B(x) (1<<(x))typedef long long ll;const int oo=0x3f3f3f3f;const ll OO=1LL<<61;const int MOD=10007;const int maxn=51000;int Rank[maxn],SA[maxn],height[maxn];int t1[maxn],t2[maxn],t3[maxn],t4[maxn];char str[maxn];int tol,n;struct CHAR{    char ch;    int p;}in[205];void Swap(int*& x,int*& y){    int *temp=x;    x=y;    y=temp;}bool cmp(int t[],int a,int b,int l){    return t[a]==t[b]&&t[a+l]==t[b+l];}void build_SA(char s[],int len,int up){    int *k1=t1,*k2=t2,*r=t3,*cnt=t4;    for(int i=0;i<up;i++)cnt[i]=0;    for(int i=0;i<len;i++)cnt[k1[i]=s[i]]++;    for(int i=1;i<up;i++)cnt[i]+=cnt[i-1];    for(int i=len-1;i>=0;i--)SA[--cnt[k1[i]]]=i;    for(int d=1,p=1;p<len;d<<=1,up=p){        p=0;        for(int i=len-d;i<len;i++)k2[p++]=i;        for(int i=0;i<len;i++)if(SA[i]>=d)k2[p++]=SA[i]-d;        for(int i=0;i<len;i++)r[i]=k1[k2[i]];        for(int i=0;i<up;i++)cnt[i]=0;        for(int i=0;i<len;i++)cnt[r[i]]++;        for(int i=1;i<up;i++)cnt[i]+=cnt[i-1];        for(int i=len-1;i>=0;i--)SA[--cnt[r[i]]]=k2[i];        Swap(k1,k2);        k1[SA[0]]=0;        p=1;        for(int i=1;i<len;i++){            k1[SA[i]]= cmp(k2,SA[i-1],SA[i],d) ? p-1 : p++;        }    }}void get_height(char s[],int len){    for(int i=1;i<=len;i++)Rank[SA[i]]=i;    for(int i=0,p=0;i<len;i++){        int j=SA[Rank[i]-1];        while(s[i+p]==s[j+p])p++;        height[Rank[i]]=p;        if(p)p--;    }}int dp[maxn][40];void rmq_init(int n){    int m=floor(log(n+0.0)/log(2.0));    for(int i=1;i<=n;i++)dp[i][0]=height[i];    for(int j=1;j<=m;j++){        for(int i=n;i;i--){            dp[i][j]=dp[i][j-1];            if(i+B(j-1)<=n){                dp[i][j]=min(dp[i][j],dp[i+B(j-1)][j-1]);            }        }    }}int rmq_query(int l,int r){    int a=Rank[l],b=Rank[r];    if(a>b)swap(a,b);    a++;    int k=floor(log(b-a+1.0)/log(2.0));    return min(dp[a][k],dp[b-B(k)+1][k]);}void Insert(char ch,int pos){    int i;    for(i=0;i<tol;i++){        if(in[i].p>=pos)break;        else pos--;    }    if(pos>n)pos=n;    int s=i;    for(i=tol++;i>s;i--)in[i]=in[i-1];    in[s].ch=ch;    in[s].p=pos;}int query(int a,int b){    int x,y,t,res=0;    for(x=0;in[x].p<=a;x++);    for(y=0;in[y].p<=b;y++);    if(a==b) return n-a+tol-x-1;///如果相等要特判    while(1){        int i=in[x].p-a,j=in[y].p-b;        int t=min(rmq_query(a,b),min(i,j));        res+=t,a+=t,b+=t;        if(t==i||t==j){            while(in[x].p==a&&in[y].p==b){                if(in[x].ch==in[y].ch) x++,y++,res++;                else return res;            }            while(in[x].p==a){                if(in[x].ch==str[b]) x++,b++,res++;                else return res;            }            while(in[y].p==b){                if(str[a]==in[y].ch) a++,y++,res++;                else return res;            }        }else return res;    }    return res;}char cmd[5];int main(){    int q,a,b;    while(scanf("%s",str)!=EOF){        n=strlen(str);        tol=1;        in[0].p=maxn;        in[0].ch=0;        build_SA(str,n+1,130);        get_height(str,n);        rmq_init(n);        scanf("%d",&q);        while(q--){            scanf("%s",cmd);            if(cmd[0]=='Q'){                scanf("%d %d",&a,&b);                printf("%d\n",query(a-1,b-1));            }else{                scanf("%s %d",cmd,&a);                Insert(cmd[0],a-1);            }        }    }    return 0;}/***/




0 0