• CF1073G Yet Another LCP Problem [后缀自动机,虚树,dp]


    题目

    题意:

    题目翻译很清楚,告辞。

    sol:

    我们考虑到 (lcp(x,y)) 等价于反串SAM上的 (dep_{lca(x,y)})

    然后我们对 给出串的反串 建一个后缀自动机,然后记一下 (pos_x)(x) 这个位置在后缀自动机上的节点位置。

    怎么求 (sum_{ain A} sum_{b in B} lca(a,b))

    考虑给出的集合 (sum A,sum B leq 4 imes10^5)

    我们直接虚树就好了吧。如果你做过品酒大会,你应该会下面这个套路。

    // powered by c++11
    // by Isaunoya
    #include <bits/stdc++.h>
    #define rep(i, x, y) for (register int i = (x); i <= (y); ++i)
    #define Rep(i, x, y) for (register int i = (x); i >= (y); --i)
    using namespace std;
    using db = double;
    using ll = long long;
    using uint = unsigned int;
    using ull = unsigned long long;
    using pii = pair<int, int>;
    #define Tp template
    #define fir first
    #define sec second
    Tp<class T> void cmax(T& x, const T& y) {
      if (x < y) x = y;
    }
    Tp<class T> void cmin(T& x, const T& y) {
      if (x > y) x = y;
    }
    #define all(v) v.begin(), v.end()
    #define sz(v) ((int)v.size())
    #define pb emplace_back
    Tp<class T> void sort(vector<T>& v) { sort(all(v)); }
    Tp<class T> void reverse(vector<T>& v) { reverse(all(v)); }
    Tp<class T> void unique(vector<T>& v) { sort(all(v)), v.erase(unique(all(v)), v.end()); }
    inline void reverse(string& s) { reverse(s.begin(), s.end()); }
    const int SZ = 1 << 23 | 233;
    struct FILEIN {
      char qwq[SZ], *S = qwq, *T = qwq, ch;
    #ifdef __WIN64
    #define GETC getchar
    #else
      inline char GETC() { return (S == T) && (T = (S = qwq) + fread(qwq, 1, SZ, stdin), S == T) ? EOF : *S++; }
    #endif
      inline FILEIN& operator>>(char& c) {
        while (isspace(c = GETC()))
          ;
        return *this;
      }
      inline FILEIN& operator>>(string& s) {
        s.clear();
        while (isspace(ch = GETC()))
          ;
        if (!~ch) return *this;
        s = ch;
        while (!isspace(ch = GETC()) && ~ch) s += ch;
        return *this;
      }
      inline FILEIN& operator>>(char* str) {
        char* cur = str;
        while (*cur) *cur++ = 0;
        cur = str;
        while (isspace(ch = GETC()))
          ;
        if (!~ch) return *this;
        *cur = ch;
        while (!isspace(ch = GETC()) && ~ch) *++cur = ch;
        *++cur = 0;
        return *this;
      }
      Tp<class T> inline void read(T& x) {
        bool f = 0;
        while ((ch = GETC()) < 48 && ~ch) f ^= (ch == 45);
        x = ~ch ? (ch ^ 48) : 0;
        while ((ch = GETC()) > 47) x = x * 10 + (ch ^ 48);
        x = f ? -x : x;
      }
      inline FILEIN& operator>>(int& x) { return read(x), *this; }
      inline FILEIN& operator>>(ll& x) { return read(x), *this; }
      inline FILEIN& operator>>(uint& x) { return read(x), *this; }
      inline FILEIN& operator>>(ull& x) { return read(x), *this; }
      inline FILEIN& operator>>(double& x) {
        read(x);
        bool f = x < 0;
        x = f ? -x : x;
        if (ch ^ '.') return *this;
        double d = 0.1;
        while ((ch = GETC()) > 47) x += d * (ch ^ 48), d *= .1;
        return x = f ? -x : x, *this;
      }
    } in;
    struct FILEOUT {
      const static int LIMIT = 1 << 22;
      char quq[SZ], ST[233];
      int sz, O, pw[233];
      FILEOUT() {
        set(7);
        rep(i, pw[0] = 1, 9) pw[i] = pw[i - 1] * 10;
      }
      ~FILEOUT() { flush(); }
      inline void flush() { fwrite(quq, 1, O, stdout), fflush(stdout), O = 0; }
      inline FILEOUT& operator<<(char c) { return quq[O++] = c, *this; }
      inline FILEOUT& operator<<(string str) {
        if (O > LIMIT) flush();
        for (char c : str) quq[O++] = c;
        return *this;
      }
      inline FILEOUT& operator<<(char* str) {
        if (O > LIMIT) flush();
        char* cur = str;
        while (*cur) quq[O++] = (*cur++);
        return *this;
      }
      Tp<class T> void write(T x) {
        if (O > LIMIT) flush();
        if (x < 0) {
          quq[O++] = 45;
          x = -x;
        }
        do {
          ST[++sz] = x % 10 ^ 48;
          x /= 10;
        } while (x);
        while (sz) quq[O++] = ST[sz--];
      }
      inline FILEOUT& operator<<(int x) { return write(x), *this; }
      inline FILEOUT& operator<<(ll x) { return write(x), *this; }
      inline FILEOUT& operator<<(uint x) { return write(x), *this; }
      inline FILEOUT& operator<<(ull x) { return write(x), *this; }
      int len, lft, rig;
      void set(int l) { len = l; }
      inline FILEOUT& operator<<(double x) {
        bool f = x < 0;
        x = f ? -x : x, lft = x, rig = 1. * (x - lft) * pw[len];
        return write(f ? -lft : lft), quq[O++] = '.', write(rig), *this;
      }
    } out;
    #define int long long
    struct Math {
      vector<int> fac, inv;
      int mod;
      void set(int n, int Mod) {
        fac.resize(n + 1), inv.resize(n + 1), mod = Mod;
        rep(i, fac[0] = 1, n) fac[i] = fac[i - 1] * i % mod;
        inv[n] = qpow(fac[n], mod - 2);
        Rep(i, n - 1, 0) inv[i] = inv[i + 1] * (i + 1) % mod;
      }
      int qpow(int x, int y) {
        int ans = 1;
        for (; y; y >>= 1, x = x * x % mod)
          if (y & 1) ans = ans * x % mod;
        return ans;
      }
      int C(int n, int m) {
        if (n < 0 || m < 0 || n < m) return 0;
        return fac[n] * inv[m] % mod * inv[n - m] % mod;
      }
      int gcd(int x, int y) { return !y ? x : gcd(y, x % y); }
      int lcm(int x, int y) { return x * y / gcd(x, y); }
    } math;
    
    int n;
    const int maxn = 4e5 + 54;
    
    vector<int> g[maxn];
    struct suffixautomaton {
      int las, cnt;
      suffixautomaton() { las = cnt = 1; }
      int ch[maxn][26], fa[maxn], len[maxn], pos[maxn];
    
      void ins(int c, int id) {
        int p = las, np = las = ++cnt;
        len[np] = len[p] + 1, pos[id] = np;
        for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
        if (!p) {
          fa[np] = 1;
        } else {
          int q = ch[p][c];
          if (len[q] == len[p] + 1) {
            fa[np] = q;
          } else {
            int nq = ++cnt;
            memcpy(ch[nq], ch[q], sizeof(ch[q]));
            len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
            for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
          }
        }
      }
    
      void ins(char* S) {
        char* Cur = S;
        int qwq = 0;
        while (*Cur) ins((*Cur++) - 'a', ++qwq);
      }
    
      void build() { rep(i, 2, cnt) g[fa[i]].pb(i); }
    } sam;
    
    int dfn[maxn], ed[maxn], idx = 0;
    
    struct LCA {
      int f[maxn][22], dep[maxn];
    
      void dfs(int u) {
        dfn[u] = ++idx;
        for (int v : g[u]) dep[v] = dep[u] + 1, f[v][0] = u, dfs(v);
        ed[u] = ++idx;
      }
    
      void solve() {
        dfs(1);
        rep(j, 1, 20) rep(i, 1, sam.cnt) f[i][j] = f[f[i][j - 1]][j - 1];
      }
    
      int lca(int x, int y) {
        if (dep[x] < dep[y]) x ^= y ^= x ^= y;
        for (int i = 20; ~i; i--)
          if (dep[f[x][i]] >= dep[y]) x = f[x][i];
        if (x == y) return x;
        for (int i = 20; ~i; i--)
          if (f[x][i] ^ f[y][i]) {
            x = f[x][i], y = f[y][i];
          }
        return f[x][0];
      }
    } Lca;
    
    // lcp = rev sam
    
    char s[maxn];
    
    struct Tree {
      int dp[maxn][2], op[maxn << 1], tot = 0, st[maxn], top = 0;
      bool book[maxn];
    
      int solve(int k1, int k2) {
        tot = 0;
        rep(i, 1, k1) {
          int x;
          in >> x, x = n - x + 1, x = sam.pos[x], dp[x][0] = 1;
          if (!book[x]) op[++tot] = x, book[x] = 1;
        }
        rep(i, 1, k2) {
          int x;
          in >> x, x = n - x + 1, x = sam.pos[x], dp[x][1] = 1;
          if (!book[x]) op[++tot] = x, book[x] = 1;
        }
        sort(op + 1, op + tot + 1, [](int x, int y) { return dfn[x] < dfn[y]; });
        for (int i = 1, lim = tot; i < lim; ++i) {
          int lca = Lca.lca(op[i], op[i + 1]);
          if (!book[lca]) op[++tot] = lca, book[lca] = 1;
        }
        rep(i, 1, tot) book[op[i]] = false;
        for (int i = 1, lim = tot; i <= lim; ++i) op[++tot] = -op[i];
        sort(op + 1, op + tot + 1,
             [](int x, int y) { return (x > 0 ? dfn[x] : ed[-x]) < (y > 0 ? dfn[y] : ed[-y]); });
        int ans = 0;
        rep(i, 1, tot) {
          if (op[i] > 0) {
            int u = op[i];
            st[++top] = u, ans += sam.len[u] * dp[u][0] * dp[u][1];
          } else {
            if (top == 1) {
              dp[st[top]][0] = dp[st[top]][1] = 0, top--;
            } else {
              int u = st[top--], f = st[top];
              ans += sam.len[f] * (dp[f][0] * dp[u][1] + dp[f][1] * dp[u][0]);
              dp[f][0] += dp[u][0], dp[f][1] += dp[u][1], dp[u][0] = dp[u][1] = 0;
            }
          }
        }
        return ans;
      }
    } tree;
    
    signed main() {
      // code begin.
      int _;
      in >> n >> _ >> s;
      reverse(s, s + n), sam.ins(s), sam.build(), Lca.solve();
      while (_--) {
        int k1, k2;
        in >> k1 >> k2;
        out << tree.solve(k1, k2) << '
    ';
      }
      return 0;
      // code end.
    }
    
  • 相关阅读:
    寒假Day37:设计模式(封装+继承+多态等)
    INF ClassInstall32 Section详解
    VS2008编译的程序运行提示“由于应用程序配置不正确,应用程序未能启动”
    INF Models Section
    INF DDInstall.Services Section
    INF ClassInstall32.Services Section详解
    INF DDInstall Section
    INF SourceDisksNames Section 和 SourceDisksFiles Section详解
    sys文件查看DbgPrint函数打印的信息
    IRP(I/O Request Package)详解
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/12585483.html
Copyright © 2020-2023  润新知