【BZOJ 3879】SvT

http://www.lydsy.com/JudgeOnline/problem.php?id=3879

SvT的中文是后缀虚树?

反正本蒟蒻不懂,还是$O(nlogn)$的后缀数组和单调栈维护来做,fye学姐讲了这种学法(当时并没有听懂QwQ),xiaoyimi教会了我这种做法→xiaoyimi的题解

一开始贡献了2次TLE,以为是玄学的死循环,果断挂起对拍器拍了一晚上,然后在回家的路上才想起来TLE是因为提交的时候忘删freopen了

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 500003;
const ll p = 23333333333333333ll;
int in() {
    int k = 0, fh = 1; char c = getchar();
    for(; c < '0' || c > '9'; c = getchar())
        if (c == '-') fh = -1;
    for(; c >= '0' && c <= '9'; c = getchar())
        k = (k << 3) + (k << 1) + c - '0';
    return k * fh;
}
  
int c[N], t1[N], t2[N];
  
void st(int *x, int *y, int *sa, int n, int m) {
    for(int i = 0; i < m; ++i) c[i] = 0;
    for(int i = 0; i < n; ++i) ++c[x[y[i]]];
    for(int i = 1; i < m; ++i) c[i] += c[i - 1];
    for(int i = n - 1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i];
}
  
void mkhz(int *r, int *sa, int n, int m) {
    int *x = t1, *y = t2, *t, p, i, j;
    for(i = 0; i < n; ++i) x[i] = r[i], y[i] = i;
    st(x, y, sa, n, m);
    for(p = 1, j = 1; p < n; m = p, j <<= 1) {
        for(p = 0, i = n - j; i < n; ++i) y[p++] = i;
        for(i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
        st(x, y, sa, n, m);
        for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; ++i)
            x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + j] == y[sa[i - 1] + j] ? p - 1 : p++;
    }
}
  
void mkh(int *r, int *sa, int *rank, int *h, int n) {
    int k = 0, j, i;
    for(i = 0; i < n; ++i) rank[sa[i]] = i;
    for(i = 1; i < n; h[rank[i++]] = k)
        for(k ? --k : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; ++k);
}
  
char s[N];
int n, m, sa[N], rank[N], r[N], h[N], f[N][20], Log_2[N], a[N];
  
int get_min(int l, int r) {
    int len = Log_2[r - l];
    return min(f[l][len], f[r - (1 << len)][len]);
}
  
int get_LCP(int l, int r) {
    l = rank[l]; r = rank[r];
    if (l > r) swap(l, r);
    return get_min(l, r);
}
  
bool cmp(int x, int y) {
    return rank[x] < rank[y];
}
  
int sta[N], top, bef[N], size[N];
  
void sub(ll &x, ll y) {
    x -= y; if (x < 0) x += p;
}
  
void add(ll &x, ll y) {
    x += y; if (x > p) x -= p;
}
  
int main() {
    n = in(); m = in();
    scanf("%s", s + 1);
    r[0] = 0;
    for(int i = 1; i <= n; ++i) r[i] = s[i] - 'a' + 1;
    mkhz(r, sa, n + 1, 27);
    mkh(r, sa, rank, h, n + 1);
      
    for(int i = 0; i < n; ++i) f[i][0] = h[i + 1];
    for(int j = 1; j < 20; ++j)
        for(int i = 0; i < n; ++i) {
            if (i + (1 << (j - 1)) >= n) break;
            f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
        }
      
    int tmp = 0;
    for(int i = 1; i <= n; ++i) {
        if ((1 << (tmp + 1)) < i) ++tmp;
        Log_2[i] = tmp;
    }
      
    int tot; ll sum, ans = 0;
    while (m--) {
        tot = in();
        for(int i = 1; i <= tot; ++i) a[i] = in();
        sort(a + 1, a + tot + 1, cmp);
        tot = unique(a + 1, a + tot + 1) - a;
        --tot;
        for(int i = 1; i < tot; ++i) bef[i] = get_LCP(a[i], a[i + 1]);
          
        top = 0; sum = 0; ans = 0;
        for(int i = 1; i < tot; ++i) {
            size[i] = 1;
            while (top && bef[i] < bef[sta[top]]) {
                sub(sum, 1ll * bef[sta[top]] * size[sta[top]] % p);
                size[i] += size[sta[top]];
                --top;
            }
            sta[++top] = i;
            add(sum, 1ll * bef[i] * size[i] % p);
            add(ans, sum);
        }
        printf("%lld\n", ans);
    }
      
    return 0;
}

再一次被自己的智商感动QAQ

posted @ 2016-08-15 21:42  abclzr  阅读(967)  评论(0编辑  收藏  举报