【CF710F】String Set Queries

题面

https://www.luogu.org/problem/CF710F

题解

删除的情况另开一个“可支持插入的$AC$自动机”,因为贡献可减。

支持插入的$AC$自动机$=$$AC$自动机$+$二进制分组。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#define ri register int
#define N 300300
#define pb push_back

using namespace std;
struct node {
  int son[26],fail,v;
} t[N];
int st[N],top;
int newnode() {
  return st[top--];
}
void insert(int u,string s){
  for (ri i=0,l=s.size();i<l;i++) {
    if (!t[u].son[s[i]-97]) t[u].son[s[i]-97]=newnode();
    u=t[u].son[s[i]-97];
  }
  t[u].v++;
}

void del(int rt){
  if (!rt) return;
  for (ri i=0;i<26;i++) del(t[rt].son[i]),t[rt].son[i]=0;
  t[rt].fail=t[rt].v=0; st[++top]=rt;
}

struct group {
  vector<string> p; int tot,rt;
  void insert(string s) {
    p.pb(s);
    ++tot;
  }
  void clear() {
    del(rt); 
    rt=newnode(); 
    p.clear(); 
    tot=0;
  }
  void build() {
    del(rt);
    rt=newnode();
    for (ri i=0;i<tot;++i) Insert(rt,p[i]);
    queue<int> q;
    t[rt].fail=rt;
    for (ri i=0;i<26;i++) if (t[rt].son[i]) q.push(t[rt].son[i]),t[t[rt].son[i]].fail=rt;
    while (!q.empty()) {
      int u=q.front(); q.pop();
      for (ri i=0;i<26;i++) if (t[u].son[i]) {
        int p=t[u].fail,v=t[u].son[i];
        while (p!=rt && !t[p].son[i]) p=t[p].fail;
        if (t[p].son[i]) t[v].fail=t[p].son[i]; else t[v].fail=rt;
        q.push(v);
        t[v].v+=t[t[v].fail].v;
      }
    }
  }
  
  int query(string s) {
    int ret=0,u=rt;
    for (ri i=0,l=s.size();i<l;i++) {
      int c=s[i]-97;
      if (t[u].son[c]) u=t[u].son[c];
      else {
        int p=t[u].fail;
        while (p!=rt && !t[p].son[c]) p=t[p].fail;
        if (t[p].son[c]) u=t[p].son[c];
        else u=rt;
      }
      ret+=t[u].v;
    }
    return ret;
  }
} A[20],B[20];

int tp1,tp2;
void insert(string s){
  ++tp1; A[tp1].clear(); A[tp1].insert(s);
  while (tp1>1 && A[tp1].tot==A[tp1-1].tot) {
    for (ri i=0;i<A[tp1].tot;i++) A[tp1-1].insert(A[tp1].p[i]);
    A[tp1--].clear();
  }
  A[tp1].build();
}
void delete(string s){
  ++tp2; B[tp2].clear(); B[tp2].insert(s);
  while (tp2>1 && B[tp2].tot==B[tp2-1].tot) {
    for (ri i=0;i<B[tp2].tot;i++) B[tp2-1].insert(B[tp2].p[i]);
    B[tp2--].clear();
  }
  B[tp2].build();
}
int query(string s){
  int ret=0;
  for (ri i=1;i<=tp1;i++) ret+=A[i].query(s);
  for (ri i=1;i<=tp2;i++) ret-=B[i].query(s);
  return ret;
}
string s;
int main(){
  ios::sync_with_stdio(false);
  for (ri i=1;i<N;i++) st[++top]=i;
  int m,opt;
  cin>>m;
  for (ri i=1;i<=m;i++) {
    cin>>opt>>s;
    if (opt==1) insert(s);
    if (opt==2) Delete(s);
    if (opt==3) cout<<query(s)<<endl;
  }
}

 

转载于:https://www.cnblogs.com/shxnb666/p/11279485.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值