• [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
    " , ans);
                    for (unsigned i = 0; i < mem.size(); ++i) {
                            b[mem[i]].clear();
                            mark[mem[i]] = false;
                    }
                    mem.clear();
            }
            
            return 0;
        
    }
  • 相关阅读:
    spark rdd--分区理解
    2020-05-03 助教一周小结(第十二周)
    2020-04-26 助教一周小结(第十一周)
    2020-04-19 助教一周小结(第十周)
    2020-04-12 助教一周小结(第九周)
    2020-04-05 助教一周小结(第八周)
    2020-03-29 助教一周小结(第七周)
    2020-03-22 助教一周小结(第六周)
    内网渗透思考(实践)
    2020-03-15 助教一周小结(第五周)
  • 原文地址:https://www.cnblogs.com/evenbao/p/10928133.html
Copyright © 2020-2023  润新知