DIVLJAK —— ac自动机

应该能进

题意:

现在有n个字符串,q个询问,每次询问有两种操作:
1 s 给你一个串s
2 x 问你在一开始给你的n个字符串中第x个字符串,是后来给你的字符串中多少个的子串。

题解:

这题 比赛的时候没看,因为被别的水题卡住了。其实就是一个ac自动机模板题一样的水题,只需要对n个字符串建树,然后每次增加字符串的时候跑一遍即可,但是要注意同一个字符串每个点最多只能增加一次,所以需要一个vis数组查看当前点是否这次已经标记过了。

#include
using namespace std;
#define ll long long
const int N=2e6+5,R=26;
bool vis[N];
vector<int>vec;
struct Tire{
    int nxt[N][R],fail[N],ed[N],num[N];
    int rt,tot,cnt;
    int newnode(){
        for(int i=0;i<R;i++)nxt[tot][i]=-1;
        ed[tot]=0;
        return tot++;
    }
    void init(){
        memset(num,0,sizeof(num));
        tot=cnt=0;
        rt=newnode();
    }
    int insert(char *s){
        int now=rt,len=strlen(s);
        for(int i=0;i<len;i++){
            int val=s[i]-'a';
            if(nxt[now][val]==-1)nxt[now][val]=newnode();
            now=nxt[now][val];
        }
        return now;
    }
    void build(){
        queue<int>q;
        fail[rt]=rt;
        for(int i=0;i<R;i++){
            if(nxt[rt][i]==-1)nxt[rt][i]=rt;
            else {
                fail[nxt[rt][i]]=rt;
                q.push(nxt[rt][i]);
            }
        }
        while(!q.empty()){
            int now=q.front();q.pop();
            for(int i=0;i<R;i++){
                if(nxt[now][i]==-1)nxt[now][i]=nxt[fail[now]][i];
                else {
                    fail[nxt[now][i]]=nxt[fail[now]][i];
                    q.push(nxt[now][i]);
                }
            }
        }
    }
    void update(char *s){
        vec.clear();
        int len=strlen(s);
        int now=rt;
        for(int i=0;i<len;i++){
            now=nxt[now][s[i]-'a'];
            int ret=now;
            while(ret!=rt){
                if(vis[ret])break;
                vis[ret]=1,vec.push_back(ret);
                ed[ret]++,ret=fail[ret];
            }
        }
        for(auto j:vec)vis[j]=0;
    }
}ac;
char s[N],ss[N];
int p[N];
int main()
{
    int n;
    scanf("%d",&n);
    ac.init();
    for(int i=1;i<=n;i++)
        scanf("%s",s),p[i]=ac.insert(s);
    ac.build();
    int q;
    scanf("%d",&q);
    while(q--){
        int op,x;
        scanf("%d",&op);
        if(op==1)
            scanf("%s",s),ac.update(s);
        else
            scanf("%d",&x),printf("%d\n",ac.ed[p[x]]);
    }
    return 0;
}


你可能感兴趣的:(AC自动机)