[BZOJ 3879] SvT

[题目链接]

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

[算法]

        首先 , 后缀树有一个很好的性质 :

        两个后缀的LCP等于该字符串反串后缀树上所对应的两个节点的最近公共祖先u的right集合中最长的串 , 即maxlen(u)

        注意到sigma(Ti)比较小 , 考虑首先构建后缀自动机 , 对于每组询问定位每个后缀在后缀树上的位置 , 建出虚树 , 在虚树上动态规划

        时间复杂度 : O(|S| + T)

[代码]

       

#include<bits/stdc++.h>
using namespace std;

#ifndef LOCAL
        #define eprintf(...) fprintf(stderr, _VA_ARGS_)
#else
        #define eprintf(...) 42
#endif

typedef long long ll;
typedef pair<int , int> pii;
typedef pair<ll , int> pli;
typedef pair<ll , ll> pll;
typedef vector< int > VI;
typedef long double ld;
typedef unsigned long long ull;
#define mp make_pair
#define fi first
#define se second
const int N = 1e6 + 10;
const int M = 3e6 + 10;
const int ALPHA = 26;
const int MAXLOG = 22;
const ll P = 23333333333333333;

int n , sz , timer , last , top , m;
int dfn[N] , depth[N] , child[N][ALPHA] , a[M] , anc[N][MAXLOG] , mark[N] , 
        size[N] , father[N] , stk[N] , lc[N] , dep[N];
char s[N];
ll ans;
VI e[N] , b[N];
VI mem;

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x) {
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}

inline int new_node(int dep) {
        depth[++sz] = dep;
        memset(child[sz] , 0 , sizeof(child[sz]));
        father[sz] = 0;
        return sz;
}
inline void extend(int ch) {
    int np = new_node(depth[last] + 1);
    int p = last;
    while (child[p][ch] == 0) {
        child[p][ch] = np;
        p = father[p];
    }
    if (child[p][ch] == np)
        father[np] = 1;
    else {
        int q = child[p][ch];
        if (depth[q] == depth[p] + 1)
            father[np] = q;
        else {
            int nq = new_node(depth[p] + 1);
            father[nq] = father[q];
            father[np] = father[q] = nq;
            memcpy(child[nq], child[q], sizeof(child[q]));
            while (child[p][ch] == q) {
                child[p][ch] = nq;
                p = father[p];
            }
        }
    }
    last = np;
}
inline void dfs(int u , int par) {
        dfn[u] = ++timer;
        dep[u] = dep[par] + 1;
        anc[u][0] = par;
        for (int i = 1; i < MAXLOG; ++i) 
                anc[u][i] = anc[anc[u][i - 1]][i - 1];
        for (unsigned i = 0; i < e[u].size(); ++i) {
                dfs(e[u][i] , u);
        }
}
inline void work( ) {
        for (int i = 1; i <= sz; ++i) {
                e[father[i]].push_back(i);
        }
        dfs( 1 , 0 );
} 
inline int getlca(int x , int y) {
        if (dep[x] > dep[y]) swap(x , y);
        for (int i = MAXLOG - 1; i >= 0; --i)
                 if (dep[anc[y][i]] >= dep[x])
                         y = anc[y][i];
        if (x == y) return x;
        for (int i = MAXLOG - 1; i >= 0; --i) 
                if (anc[x][i] != anc[y][i])
                        x = anc[x][i] , y = anc[y][i];
        return anc[x][0];
}
inline void insert(int u) {
        mem.push_back(u);
        if (top <= 1) { stk[++top] = u; return; }
        int lca = getlca(u , stk[top]);
        if (lca == stk[top]) { stk[++top] = u; return; }
        while (top > 1 && dfn[lca] <= dfn[stk[top - 1]]) {
                b[stk[top]].push_back(stk[top - 1]);
                b[stk[top - 1]].push_back(stk[top]);
                --top;
        }
        mem.push_back(lca);
        if (stk[top] != lca) {
                b[lca].push_back(stk[top]);
                b[stk[top]].push_back(lca);
                stk[top] = lca;
        }
        stk[++top] = u;
} 
inline void calc(int u , int par) {
        ll cnt = 0;
        size[u] = 0;
        for (int i = 0; i < b[u].size(); ++i) {
                int v = b[u][i];
                if (v == par) continue;
                calc(v , u);
                size[u] += size[v];
                cnt = (cnt + 1LL * size[v] * (size[u] - size[v]) % P) % P;
        }
        if (mark[u]) {
                cnt = (cnt + size[u]) % P;
                ++size[u];
        }
        ans = (ans + 1LL * depth[u] * cnt) % P;
}
inline bool cmp(int x , int y) {
        return dfn[x] < dfn[y];
}

int main() {
        
        scanf("%d%d" , &n , &m);
        scanf("%s" , s + 1);
        reverse(s + 1 , s + n + 1);
        sz = last = 1;
        for (int i = 1; i <= n; ++i) {
                extend(s[i] - 'a');
                lc[i] = last;
        }
        work();
        while (m--) {
                int q;
                read(q);
                for (int i = 1; i <= q; ++i) {
                        int x;
                        read(x);
                        a[i] = lc[n - x + 1];
                        mark[a[i]] = true;
                }
                a[++q] = 1;
                sort(a + 1 , a + q + 1 , cmp);
                top = 0;
                for (int i = 1; i <= q; ++i) {
                         if (a[i] != a[i - 1])
                                 insert(a[i]);
                }
                while (top > 1) {
                        b[stk[top]].push_back(stk[top - 1]);
                        b[stk[top - 1]].push_back(stk[top]);
                        --top;
                }
                ans = 0;
                calc(1 , 0);
                printf("%lld\n" , ans);
                for (unsigned i = 0; i < mem.size(); ++i) {
                        b[mem[i]].clear();
                        mark[mem[i]] = false;
                }
                mem.clear();
        }
        
        return 0;
    
}

 

posted @ 2019-05-26 22:41  evenbao  阅读(373)  评论(0编辑  收藏  举报