CF710F String Set Queries

CF710F String Set Queries 

支持字符串的插入和删除。。。SAM也干不了这个事

所以可以用cdq分治+AC自动机O(nlogn)解决

但是本题强制在线~~~

我们还有一个工具,叫做二进制分组!

所以,每组建立一个AC自动机,合并的时候,AC自动机合并。最后再build失配指针

随机删除?虽然不是栈序删除了,但是,统计数量具有贡献独立性,再对删除串建立一个AC自动机集群即可!

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=3e5+5;
int m;
int ch[N][26];
int vis[N][26];
int fail[N],num[N],tot[N];
int rt[N],sz[N];    
int cnt,totid;
struct AC{
    int sta[N],top;
    int merge(int x,int y){
    //    cout<<"merge "<<x<<" "<<y<<endl;
        if(!x||!y) return x+y;
        for(reg i=0;i<26;++i) ch[x][i]=merge(ch[x][i],ch[y][i]);
        num[x]+=num[y];
        return x;
    }
    void build(int id){
        queue<int>q;
        for(reg i=0;i<26;++i){
            if(ch[rt[id]][i]) fail[vis[rt[id]][i]=ch[rt[id]][i]]=rt[id],q.push(vis[rt[id]][i]);
            else vis[rt[id]][i]=rt[id];
        }
        while(!q.empty()){
            int x=q.front();q.pop();
            tot[x]=num[x]+tot[fail[x]];
            for(reg i=0;i<26;++i){
                if(ch[x][i]){
                    fail[vis[x][i]=ch[x][i]]=vis[fail[x]][i];
                    q.push(vis[x][i]);
                }else{
                    vis[x][i]=vis[fail[x]][i];
                }
            }
        }
    }
    int query(char *s){
        int len=strlen(s+1);
        int ret=0;
        for(reg i=1;i<=top;++i){
            int id=sta[i];
            int now=rt[id];
            for(reg i=1;i<=len;++i){
                now=vis[now][s[i]-'a'];
                ret+=tot[now];
            }
        }
        return ret;
    }
    void ins(char *s){
        int id=++totid;
        int len=strlen(s+1);
        if(!rt[id]) rt[id]=++cnt;
        int now=rt[id];
        for(reg i=1;i<=len;++i){
            int x=s[i]-'a';
            ch[now][x]=++cnt;
            now=ch[now][x];
        }
        ++num[now];
        //dfs(rt[id]);
    //    cout<<rt[id]<<" "<<cnt<<endl;
        sz[id]=1;
    //    cout<<" after ins "<<id<<endl;
        while(top&&sz[sta[top]]==sz[id]) rt[id]=merge(rt[id],rt[sta[top]]),sz[id]+=sz[sta[top]],--top;
    //    cout<<" after merge "<<endl;
        build(id);
        sta[++top]=id;
        
    }
}f,d;
char s[N];
int main(){
    rd(m);
    int op;
    for(reg i=1;i<=m;++i){
        rd(op);scanf("%s",s+1);
        if(op==1)f.ins(s);
        else if(op==2)d.ins(s);
        else {
            printf("%d\n",f.query(s)-d.query(s));
        }
        fflush(stdout);
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/2/24 15:19:38
*/

二进制分组,对于许多插入删除根本不虚,反正暴力重构删除,O(nlogn)

(当然如果贡献不独立,还是cdq或者线段树分治吧,,)

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/10426608.html