AcWing 2572. 生成魔咒
原题链接
困难
作者:
皓首不倦
,
2021-05-14 00:26:51
,
所有人可见
,
阅读 614
#include <algorithm>
#include <map>
using namespace std;
const int MAX_STR_LEN = 100005;
int input[MAX_STR_LEN];
int xx[MAX_STR_LEN];
int yy[MAX_STR_LEN];
int c[MAX_STR_LEN];
int sa[MAX_STR_LEN];
int rk[MAX_STR_LEN];
int height[MAX_STR_LEN];
long long ans[MAX_STR_LEN];
int ll[MAX_STR_LEN];
int rr[MAX_STR_LEN];
class SA {
private:
const int* S;
int max_char_val;
bool sa_flag;
bool height_flag;
int str_len;
public:
SA(const int* str, int max_char_val, int n) : S(str-1), max_char_val(max_char_val), sa_flag(false), height_flag(false), str_len(n) { }
int* get_sa() {
int* x = xx;
int* y = yy;
if (sa_flag) {
return sa;
}
int n = str_len, m = max_char_val;
for (int i = 1; i <= n; i ++ )
c[x[i] = S[i]] ++ ;
for (int i = 2; i <= m; i ++ )
c[i] += c[i - 1];
for (int i = n; i; i -- )
sa[c[x[i]] -- ] = i;
for (int k = 1; k <= n; k <<= 1)
{
int num = 0;
for (int i = n - k + 1; i <= n; i ++ )
y[ ++ num] = i;
for (int i = 1; i <= n; i ++ )
if (sa[i] > k)
y[ ++ num] = sa[i] - k;
for (int i = 1; i <= m; i ++ )
c[i] = 0;
for (int i = 1; i <= n; i ++ )
c[x[i]] ++ ;
for (int i = 2; i <= m; i ++ )
c[i] += c[i - 1];
for (int i = n; i; i -- )
sa[c[x[y[i]]] -- ] = y[i], y[i] = 0;
swap(x, y);
x[sa[1]] = 1, num = 1;
for (int i = 2; i <= n; i ++ )
x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++ num;
if (num == n)
break;
m = num;
}
for (int i = 1; i <= n; i ++ )
rk[sa[i]] = i;
sa_flag = true;
return sa;
}
int* get_rk() {
if (!sa_flag) {
get_sa();
}
return rk;
}
int* get_height() {
if (height_flag) {
return height;
}
if (!sa_flag) {
get_sa();
}
int n = str_len;
for (int i = 1, k = 0; i <= n; i ++ )
{
if (rk[i] == 1)
continue;
if (k)
k --;
int j = sa[rk[i] - 1];
while (i + k <= n && j + k <= n && S[i + k] == S[j + k])
k ++ ;
height[rk[i]] = k;
}
height_flag = true;
return height;
}
};
map<int, int> hh;
int hash_val = 1;
void add_hash(int val) {
if (hh.find(val) == hh.end()) {
hh[val] = hash_val++;
}
}
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &(input[n-1-i]));
add_hash(input[n-1-i]);
}
for (int i = 0; i < n; i++) {
input[i] = hh[input[i]];
}
rr[0] = 1, ll[n+1] = n;
for (int i = 1; i <= n; i++) {
ll[i] = i-1, rr[i] = i+1;
}
SA algo(input, 100005, n);
int* sa_arr = algo.get_sa();
int* h_arr = algo.get_height();
int* rk_arr = algo.get_rk();
long long tot = 0;
for (int i = 1; i <= n; i++) {
tot += n - (sa[i] - 1) - h_arr[i];
}
ans[n-1] = tot;
for (int i = 1; i<= n-1; i++) {
int rk_i = rk_arr[i];
int rk_j = rr[rk_i];
tot -= n - (sa_arr[rk_i] - 1) - h_arr[rk_i];
tot -= n - (sa_arr[rk_j] - 1) - h_arr[rk_j];
h_arr[rk_j] = min(h_arr[rk_j], h_arr[rk_i]);
tot += n - (sa_arr[rk_j] - 1) - h_arr[rk_j];
ans[n-1-i] = tot;
rr[ll[rk_i]] = rr[rk_i];
ll[rr[rk_i]] = ll[rk_i];
ll[rk_i] = rr[rk_i] = 0;
}
for (int i = 0; i < n; i++) {
printf("%lld\n", ans[i]);
}
return 0;
}