[後綴數組][trie合併][啓發式合併][並查集] LOJ #6198. 謝特

Solution

求出後綴數組heighti 後。
問題轉化爲maxij{mini<kj{heighti}+(wi xor wj)}
從大到小枚舉作爲最小值的heighti ,相當於要找到左右兩邊取一個數得到的異或和最大值。
可以啓發式合併兩邊的元素,用trie維護,每次枚舉較小列表裏的元素在另一邊詢問就好了。
時間複雜度就O(nlog2n) 了。

#include <bits/stdc++.h>
#define show(x) cerr << #x << " = " << x << endl
using namespace std;
typedef long long ll;
typedef pair<int, int> Pairs;

const int K = 18;
const int N = 202020;
const int M = 4040404;

inline char get(void) {
    static char buf[100000], *S = buf, *T = buf;
    if (S == T) {
        T = (S = buf) + fread(buf, 1, 100000, stdin);
        if (S == T) return EOF;
    }
    return *S++;
}
template<typename T>
inline void read(T &x) {
    static char c; x = 0; int sgn = 0;
    for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1;
    for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
    if (sgn) x = -x;
}
inline void read(char *c) {
    for (*c = get(); *c < 'a' || *c > 'z'; *c = get());
    for (; *c >= 'a' && *c <= 'z'; *c = get()) ++c;
    *c = 0;
}

namespace suffixArray {
    int sa[N], buc[N], x[N] , y[N];
    int rk[N], hgt[N];

    inline void pre(char *s, char *end) {
        int n = end - s;
        int m = N - 10;
        for (int i = 0; i < m; i++) buc[i] = 0;
        for (int i = 0; i < n; i++) ++buc[x[i] = s[i]];
        for (int i = 1; i < m; i++) buc[i] += buc[i - 1];
        for (int i = n - 1; i >= 0; i--) sa[--buc[x[i]]] = i;
        for (int k = 1; k <= n; k <<= 1) {
            int p = 0;
            for (int i = n - 1; i >= n - k; i--) y[p++] = i;
            for (int i = 0; i < n; i++) if (sa[i] >= k) y[p++] = sa[i] - k;
            for (int i = 0; i < m; i++) buc[i] = 0;
            for (int i = 0; i < n; i++) ++buc[x[y[i]]];
            for (int i = 1; i < m; i++) buc[i] += buc[i - 1];
            for (int i = n - 1; i >= 0; i--) sa[--buc[x[y[i]]]] = y[i];
            swap(x, y);
            p = 1; x[sa[0]] = 0;
            for (int i = 1; i < n; i++) {
                if (y[sa[i - 1]] == y[sa[i]] &&
                        y[sa[i - 1] + k] == y[sa[i] + k])
                    x[sa[i]] = p - 1;
                else x[sa[i]] = p++;
            }
            if (p >= n) break;
            m = p;
        }
        int j, k = 0;
        for (int i = 0; i < n; i++) rk[sa[i]] = i;
        for (int i = 0; i < n; i++) {
            if (rk[i] == 0) { hgt[0] = 0; continue; }
            if (k != 0) k--;
            int j = sa[rk[i] - 1];
            while (s[i + k] == s[j + k] && i + k < n && j + k < n) ++k;
            hgt[rk[i]] = k;
        }
    }
}
namespace trie {
    int tcnt;
    int ch[M][2];
    int rt[N];
    inline void _insert(int &u, int x, int d) {
        if (!u) u = ++tcnt;
        if (d < 0) return;
        _insert(ch[u][x >> d & 1], x, d - 1);
    }
    inline int _merge(int x, int y, int d) {
        if (!x || !y) return x ? x : y;
        if (d < 0) return x;
        ch[x][0] = _merge(ch[x][0], ch[y][0], d - 1);
        ch[x][1] = _merge(ch[x][1], ch[y][1], d - 1);
        return x;
    }
    inline int _query(int x, int y, int d) {
        if (d < 0) return 0;
        int k = y >> d & 1;
        if (!ch[x][k ^ 1]) return _query(ch[x][k], y, d - 1);
        else return (1 << d) | _query(ch[x][k ^ 1], y, d - 1);
    }
    inline void insert(int id, int x) {
        _insert(rt[id], x, K);
    }
    inline void merge(int from, int to) {
        rt[to] = _merge(rt[from], rt[to], K);
    }
    inline int query(int id, int y) {
        return _query(rt[id], y, K);
    }
}

using suffixArray::sa;
using suffixArray::hgt;
using trie::insert;
using trie::query;

int n, ans;
int w[N], id[N];
int fa[N], rk[N];
char s[N];
vector<int> lt[N];

inline int cmp(int x, int y) {
    return hgt[x] > hgt[y];
}
inline int getFa(int x) {
    return fa[x] == x ? x : fa[x] = getFa(fa[x]);
}
inline int merge(int x, int y) {
    static int f1, f2;
    f1 = getFa(x); f2 = getFa(y);
    if (f1 == f2) return -1;
    int res = 0;
    if (lt[f1].size() > lt[f2].size()) swap(f1, f2);
    for (int x: lt[f1]) {
        res = max(res, query(f2, x));
        lt[f2].push_back(x);
    }
    lt[f1].clear();
    trie::merge(f1, f2);
    fa[f1] = f2;
    return res;
}

int main(void) {
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
    read(n); read(s);
    for (int i = 0; i < n; i++) read(w[i]);
    suffixArray::pre(s, s + n);
    for (int i = 1; i < n; i++) id[i] = i;
    sort(id + 1, id + n, cmp);
    for (int i = 0; i < n; i++) {
        fa[i] = i; lt[i].push_back(w[i]);
        insert(i, w[i]);
    }
    for (int i = 1; i < n; i++) {
        int x = id[i];
        int res = merge(sa[x - 1], sa[x]);
        ans = max(ans, hgt[x] + res);
    }
    cout << ans << endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章