CF710F文字セットクエリ[ACオートマトン+バイナリパケット]

バイナリグループ化は、実際には、大まかなスポットを描き、その原料を下回っています。

簡単にそれぞれが唯一のもの組み込まれたことを示すために\(\ログ\)があるので、時間\(\ \ログ)私たちは彼の抽象的複雑さを理解することができるように、層がある(nは\ \ログイン\ nは\ \) されます。

そして、この質問の練習について話、我々はあなたが合併の複雑さを行うたびに私たちができることを、あなたは情報のトライを置くことができるでもそう結合され、その後、各点のACオートマトンのために再び建てつまり、制御可能であることを見つけますオンライン行います。
サブクエリ文字列の数については、私たちはうまく彼らの最後の番号を失敗するルートからツリーを照会する必要があります。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 53;
char s[maxn];
int ch[maxn][26], ed[maxn], fail[maxn], tr[maxn][26], siz[maxn];
int cnt = 1;

struct ACAM {
  int rt, sz;

  void ins(char* s) {
    int p = rt = ++cnt;
    sz = 1;
    while (*s) {
      int c = (*s++) - 'a';
      if (!ch[p][c]) ch[p][c] = ++cnt;
      p = ch[p][c];
    }
    ed[p] = 1;
  }

  void build() {
    queue<int> q;
    for (int i = 0; i < 26; i++)
      if (ch[rt][i]) {
        fail[tr[rt][i] = ch[rt][i]] = rt;
        q.push(tr[rt][i]);
      } else {
        tr[rt][i] = rt;
      }
    while (q.size()) {
      int u = q.front();
      q.pop();
      for (int i = 0; i < 26; i++) {
        if (ch[u][i]) {
          fail[tr[u][i] = ch[u][i]] = tr[fail[u]][i];
          q.push(tr[u][i]);
        } else {
          tr[u][i] = tr[fail[u]][i];
        }
      }
      siz[u] = ed[u] + siz[fail[u]];
    }
  }
};

int merge(int x, int y) {
  if (!x || !y) return x | y;
  ed[x] += ed[y];
  for (int i = 0; i < 26; i++) ch[x][i] = merge(ch[x][i], ch[y][i]);
  return x;
}

struct ACAutoMaton {
  ACAM rt[maxn];
  int top;

  ACAutoMaton() { top = 0; }

  void solve(char* s) {
    rt[++top].ins(s);
    while (top > 1 && rt[top].sz == rt[top - 1].sz) {
      rt[top - 1].rt = merge(rt[top - 1].rt, rt[top].rt);
      rt[top - 1].sz += rt[top].sz, top--;
    }
    rt[top].build();
  }

  int qry(char* s) {
    int ans = 0;
    for (int i = 1; i <= top; i++) {
      int p = rt[i].rt;
      for (char* t = s; *t;) p = tr[p][(*t++) - 'a'], ans += siz[p];
    }
    return ans;
  }
} INS, DEL;

signed main() {
  int _;
  scanf("%d", &_);
  while (_--) {
    int op;
    scanf("%d", &op), scanf("%s", s);
    if (op == 1) {
      INS.solve(s);
    }
    if (op == 2) {
      DEL.solve(s);
    }
    if (op == 3) {
      printf("%d\n", INS.qry(s) - DEL.qry(s));
      fflush(stdout);
    }
  }
  return 0;
}

おすすめ

転載: www.cnblogs.com/Isaunoya/p/12540656.html