求出後綴數組 後。
問題轉化爲
從大到小枚舉作爲最小值的 ,相當於要找到左右兩邊取一個數得到的異或和最大值。
可以啓發式合併兩邊的元素,用trie維護,每次枚舉較小列表裏的元素在另一邊詢問就好了。
時間複雜度就 了。
#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;
}