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

题目

题意:

题目翻译很清楚,告辞。

sol:

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

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

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

考虑给出的集合 \(\sum A,\sum B \leq 4\times10^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) << '\n';
  }
  return 0;
  // code end.
}
posted @ 2020-03-28 02:55  _Isaunoya  阅读(138)  评论(0编辑  收藏  举报