HDU6138 F Fleet of the Eternal Throne(字典樹+後綴數組+二分)

題目大意:給予n個字符串,有q次查詢,對於每次查詢,求出x串與y串的最長公共子串長度,該子串至少要是n個串中的一個串的前綴。

首先對輸入的n個串建立字典樹,方便查詢前綴,然後對於每次查詢輸入的x與y,把x串與y串取出來,兩個串連接在一起,中間用個沒有出現過的字符隔開,對這個串套用後綴數組模板,然後對答案二分。

對於每個二分出來的mid,按照掃描一遍height數組,如果當前的height[i]的值大於mid,而且當前的兩個串分別是x與y的後綴,而且他們的公共前綴可以在字典樹中查詢到,那麼mid就是合法的。

#include <algorithm>
#include <bitset>
#include <cassert>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <math.h>
#include <set>
#include <vector>
using namespace std;
#define Max_N (100000 + 100)
struct node{
    int next[27];
    int v;
    void init(){
        v=0;
        memset(next,-1,sizeof(next));
    }
};
struct node L[Max_N];
int tot=0;

void add(char a[],int len){
    int now=0;
    for(int i=0;i<len;i++){
        int tmp=a[i]-'a';
        int next=L[now].next[tmp];
        if(next==-1){
            next=++tot;
            L[next].v=-1;
            L[next].init();
            L[now].next[tmp]=next;
        }
        now=next;
        L[now].v++;
    }

}

int query(int a[],int len){
    int now=0;
    for(int i=0;i<len;i++){
        int tmp=a[i];
        int next=L[now].next[tmp];
        if(next==-1)return 0;
        now=next;
    }
    return L[now].v;
}
int n;
int k;
int a[Max_N];
int rank1[Max_N];
int tmp[Max_N];
bool compare_sa(int i, int j)
{
    if(rank1[i] != rank1[j]) return rank1[i] < rank1[j];
    else {
        int ri = i + k <= n ? rank1[i + k] : -1;
        int rj = j + k <= n ? rank1[j + k] : -1;
        return ri < rj;
    }
}

void construct_sa(int buf[], int s, int sa[])
{
    int len = s;
    for (int i = 0; i <= len; i++) {
        sa[i] = i;
        rank1[i] = i < len ? buf[i] : -1;
    }

    for ( k = 1; k <= len; k *= 2) {
        sort(sa, sa + len +1, compare_sa);
        tmp[sa[0]] = 0;
        for (int i = 1; i <= len; i++) {
            tmp[sa[i]] = tmp[sa[i-1]] + (compare_sa(sa[i-1], sa[i]) ? 1 : 0);
        }
        for (int i = 0; i <= len; i++) {
            rank1[i] = tmp[i];
        }
    }
}

void construct_lcp(int buf[], int len, int *sa, int *lcp)
{
    int h = 0;
    lcp[0] = 0;
    for (int i = 0; i < len; i++) {
        int j = sa[rank1[i] - 1];
        if (h > 0) h--;
        for (; j + h < len && i + h < len; h++) {
            if (buf[j+h] != buf[i+h]) break;
        }
        lcp[rank1[i] - 1] = h;
    }
}
int sa[Max_N];
int lcp[Max_N];
char buf[Max_N];
int T;
int m;
vector<int> ss;
int p[Max_N];
struct  point
{
    int l; int r;
};
point p2[Max_N];
int s1[Max_N];
int s2[Max_N];
int a1[Max_N];
bool check(int x1, int x2, int l2, int r2)
{
    if (0 <= x1 && x1 < l2 && l2 < x2 && x2 < r2) return true;
    else return false;
}
int main()
{
    
    cin >> T;
    while (T--) {
        scanf("%d", &m);
        int len = 0;
        tot = 0;
        L[0].init();
        for (int i = 0; i < m; i++) {
            scanf("%s", buf);
            //p[len2] = i+1;
            int len2 = strlen(buf);
            add(buf, len2);
            p2[i+1].l = len;
            for (int j = 0; j < len2; j++) {
                p[len] = i + 1;
                a1[len++] = buf[j] - 'a';
            }
            p[len] = 0;
            p2[i+1].r = len;
            a1[len++] = 10000+i;
        }
        int q;
        scanf("%d", &q);
        while (q--) {
            int x, y;
            scanf("%d%d", &x, &y);
            int len3 = 0;
            int len1 = 0;
            for (int i = p2[x].l; i < p2[x].r; i++) {
                s1[len1++] = a1[i];
                a[len3++] = a1[i];
            }
            int len2 = 0;
            a[len3++] = 1000;
            for (int i = p2[y].l; i < p2[y].r; i++){
                s2[len2++] = a1[i];
                a[len3++] = a1[i];
            }
            /*for (int i = 0; i < len3; i++)
                cout << a[i] << endl;*/
            n = len3;
            construct_sa(a, len3, sa);
            construct_lcp(a, len3, sa, lcp);
            int l1 = 0; int r1 = max(len1, len2);
            int ans = 0;
            while (true) {
                int mid = (r1 - l1) / 2 + l1;
                int flag = 0;
                for (int j = 1; j < n; j++) {
                    if (lcp[j] >= mid && (check(sa[j], sa[j+1], len1, len3) || check(sa[j+1], sa[j], len1, len3))) {
                        if(query(a+sa[j], mid)) {
                            flag = 1;
                            break;
                        }
                    }
                }
                if (flag == 1) {
                    ans = mid;
		            l1= mid + 1;
                }
                else r1 = mid -1;
                if (l1 > r1) break;
            }            cout << ans << endl;

        }
        
    }
    return 0;
}
  


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章