2011-07-22 08:56:31Morris

CountSort + SA

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MaxL 1048576
int Build_Height(int);

struct xy_change_rank{
    int index, v;
}Data[MaxL];
char S[MaxL], base_rank[256], Mask[MaxL];  
int s2[30]={1}, rank[MaxL], SA[MaxL], Queue[MaxL] = {-1};
int height[MaxL];
int ST[MaxL*2];
struct list {
    int v, index;
    struct list *next;
}*Count[MaxL] = {}, *curr, *prev;
int CountHeap[MaxL];
void CountSort(int C, int L) {
    int a, b;
    for(a = 1; a < C; a++) {
        for(b = Queue[a-1]+1; b <= Queue[a]; b++) {
            curr = (struct list *)malloc(sizeof(struct list));
            curr->v = a, curr->index = Data[b].index;
            prev = Count[Data[b].v];
            Count[Data[b].v] = curr, curr->next = prev;
        }
        CountHeap[a] = Queue[a-1]+1;
    }
    for(a = 0; a <= L; a++) {
        curr = Count[a];
        while(curr != NULL) {
            Data[CountHeap[curr->v]].v = a, Data[CountHeap[curr->v]].index = curr->index;
            CountHeap[curr->v]++;
            prev = curr, curr = curr->next, free(prev);
        }
        Count[a] = NULL;
    }
}
void Doubling_Algorithm() {
    int a, b, c, C, temp;
    int L=strlen(S);
    for(a = 0; a < L; a++)
        rank[a] = base_rank[S[a]], Mask[a] = 0,
        Data[a].v = rank[a], Data[a].index = a;
    C = 1, Queue[C] = L-1, C++;
    CountSort(C, 'z');
    for(a = 0; s2[a] < L; a++) {
        temp = Data[0].v, C = 1;
        for(b = 0; b < L; b++) {
            if(Data[b].v != temp || Mask[b] == 1)
                Queue[C] = b-1, temp = Data[b].v, C++, Mask[b] = 1;
            rank[Data[b].index] = C;
        }
        Queue[C] = L-1, C++;
        for(b = 0; b < L; b++) {
            if(Data[b].index + s2[a] < L) Data[b].v = rank[Data[b].index + s2[a]];
            else Data[b].v = 0;
        }
        CountSort(C, C);
    }
    for(a = 0; a < L; a++)
        SA[a] = Data[a].index;
}
int Build_Height(int L) {
    int a, b, k = 0;
    for(a = 0; a < L; a++)    rank[SA[a]] = a;
    for(a = 0; a < L; a++) {
        if(rank[a] == 0) {height[rank[a]] = 0; continue;}
        if(a == 0 || height[rank[a-1]] <= 1) k = 0;
        else k = height[rank[a-1]] - 1;
        while(S[SA[rank[a]-1]+k] == S[SA[rank[a]]+k])    k++;
        height[rank[a]] = k;
    }
}
int min(int x, int y) {
    return x < y ? x : y;
}
void initST(int l, int r, int k) {
    if(l == r)  ST[k] = height[l];
    else {
         int m = (l + r)/2;
         initST(l, m, 2*k);
         initST(m+1, r, 2*k+1);
         ST[k] = min(ST[2*k], ST[2*k+1]);
    }
}
int Getmin(int l, int r, int k, int x, int y) {
    if(l == x && r == y)  return ST[k];
    else {
         int m = (l + r)/2;
         if(m >= y) return Getmin(l, m, 2*k, x, y);
         else if(m < x) return Getmin(m+1, r, 2*k+1, x, y);
         else return min(Getmin(l, m, 2*k, x, m), Getmin(m+1, r, 2*k+1, m+1, y));
    }
}
int LCP(int i, int j, int L) {
    i = rank[i], j = rank[j];
    if(i > j) {
        int t;
        t = i, i = j, j = t;
    }
    return Getmin(0, L-1, 1, i+1, j);
}
main() {
    int a, T, C = 0;
    for(a = 1; a < 30; a++)   s2[a] = s2[a-1]*2;
    for(a = '#'; a <= 'z'; a++)   base_rank[a] = a - '#' + 1;
    scanf("%d", &T);
    getchar();
    while(T--) {
        gets(S);
        int L = strlen(S), a, b, n;
        S[L] = '#';
        for(a = L+1, b = 0; b < L; a++, b++)
            S[a] = S[L-b-1];
        S[2*L+1] = '$', S[2*L+2] = '\0';
        L = strlen(S);
        Doubling_Algorithm(), Build_Height(L);
        initST(0, L-1, 1), n = L/2-1;
        int max = 0, st, k;
        for(a = 0; a < n; a++) {
            k = LCP(a, L-a-1, L);
            if(k<<1 > max)  {
                max = k<<1;
                st = a-k;
            }
            k = LCP(a, L-a-2, L);
            if((k<<1)-1 > max)    {
                max = (k<<1) - 1;
                st = a-k+1;
            }
        }
        printf("%d\n", max);
        /*printf("%s %d\n", S, L);
        for(a = 0; a < L; a++)
            printf("%s\n", S+SA[a]);
        puts("");        
        for(a = 0; a < L; a++)
            printf("%2d ", a);
        puts("");
        for(a = 0; a < L; a++)
            printf("%2d ", SA[a]);
        puts("");
        for(a = 0; a < L; a++)
            printf("%2d ", height[a]);
        puts("");
        for(a = 0; a < L; a++)
            printf("%2d ", rank[a]);
        puts("");*/
    }
    return 0;
}