string(AC自动机 在线询问转离线询问)

:链接:https://ac.nowcoder.com/acm/problem/14612?&headNav=acm
来源:牛客网

Bob has a dictionary with N words in it. There are M operators. Each operator is one of two kinds.

 

1. Add a string to the dictionary. It is guaranteed that the string s was not added before.

2. For the given string s find the number of occurrences of the strings from the dictionary. If some string p from the dictionary has several occurrences in s you should count all of them.

题目大意:首先是T组测试样例,然后先输入n个字符串放在仓库中,然后m次询问,每一次询问有两种类型。类型1是在仓库中新添加一个字符串。类型2是输入一个字符串,然后问当前仓库中有多少字符串是你操作2输入的字符串的子串

具体思路:一开始是按照在输入新的n个字符串之后建立fail树的,然后每次查询的时候再重新建立一颗fail树(因为考虑到会添加许多新的字符串),然后就T了。既然询问次数达到了1e5.我们就可以考虑在线的强制转换为离线的算法。(多谢旭伟的提醒)

我们先将所有的字符串输入进来,然后再去建fail树。对于每次操作2,我们从输入的顺序倒着来。在初始输入阶段中,当为操作1时,我们保存当前字符串在trie树上的结尾下标。当全部输入完的

时候,倒序查询,每查询完一个,就将这个操作下面添加的字符串操作在trie树上的权值下标取消就好了。

AC代码:

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 # define ll long long
  4 # define inf 0x3f3f3f3f
  5 const int maxn = 2e5+100;
  6 string str;
  7 int tot,ch[maxn][30],val[maxn];
  8 int fail[maxn],last[maxn];
  9 struct node
 10 {
 11     int type;
 12     int end_pos;
 13     string str;
 14     node() {}
 15     node(int xx,int yy)
 16     {
 17         type=xx,end_pos=yy;
 18     }
 19 } q[maxn];
 20 int sto[maxn];
 21 int  add()
 22 {
 23     int p=0;
 24     int len=str.size();
 25     for(int i=0; i<len; i++)
 26     {
 27         int u= str[i]-'a';
 28         if(!ch[p][u])
 29             ch[p][u]=++tot;
 30         p=ch[p][u];
 31     }
 32     val[p]++;
 33     return p;
 34 }
 35 void getfail()
 36 {
 37     queue<int>q;
 38     for(int i=0;i<=tot;i++)fail[i]=-1;
 39     q.push(0);
 40     while(!q.empty())
 41     {
 42         int top=q.front();
 43         q.pop();
 44         for(int i=0; i<26; i++)
 45         {
 46             int u=ch[top][i];
 47             if(u==0)
 48                 continue;
 49             q.push(u);
 50             int v=fail[top];
 51             while(v!=-1&&!ch[v][i])
 52                 v=fail[v];
 53                 fail[u]=(v==-1?0:ch[v][i]);
 54             last[u]=val[fail[u]]?fail[u]:last[fail[u]];
 55         }
 56     }
 57 }
 58 void init()
 59 {
 60     for(int i=0; i<=tot; i++)
 61     {
 62         fail[i]=0,last[i]=0,val[i]=0;
 63         for(int j=0; j<30; j++)
 64         {
 65             ch[i][j]=0;
 66         }
 67     }
 68     tot=0;
 69 }
 70 int cal(int t)
 71 {
 72     int ans=0;
 73     while(t)
 74     {
 75         ans+=val[t];
 76         t=last[t];
 77     }
 78     return ans;
 79 }
 80 int getans(string st)
 81 {
 82     int ans=0;
 83     int len=st.size();
 84 
 85     int p=0;
 86     for(int i=0; i<len; i++)
 87     {
 88         int u=st[i]-'a';
 89         while(p&&ch[p][u]==0)
 90             p=fail[p];
 91         p=ch[p][u];
 92         if(val[p])
 93             ans+=cal(p);
 94         else if(fail[p])
 95         {
 96             ans+=cal(fail[p]);
 97         }
 98     }
 99     return ans;
100 }
101 int main()
102 {
103     ios::sync_with_stdio(false);
104     int T;
105     cin>>T;
106     //scanf("%d",&T);
107     while(T--)
108     {
109         init();
110         int n,m;
111         cin>>n>>m;
112         //scanf("%d %d",&n,&m);
113         for(int i=1; i<=n; i++)
114         {
115             cin>>str;
116             // scanf("%s",str);
117             add();
118         }
119         getfail();
120         int type;
121         int num=0;
122         while(m--)
123         {
124             cin>>type>>str;
125             //scanf("%d%s",&type,str);
126             if(type==1)
127             {
128                 q[++num].type=1;
129                 q[num].end_pos=add();
130             }
131             else
132             {
133                 q[++num].type=2;
134                 q[num].str=str;
135             }
136         }
137         getfail();
138         for(int i=num; i>=1; i--)
139         {
140             if(q[i].type==2)
141                 sto[i]=getans(q[i].str);
142             else
143             {
144                 val[q[i].end_pos]--;
145             }
146         }
147         for(int i=1; i<=num; i++)
148         {
149             if(q[i].type==2)
150             cout<<sto[i]<<endl;
151         }
152     }
153     return 0;
154 }

 

 

 

 

posted @ 2019-05-15 14:35  Let_Life_Stop  阅读(702)  评论(2编辑  收藏  举报