【BZOJ3881】【COCI2015】Divljak
这题原本xsy上有且暴力可过。。。结果考场上加了hack数据并且开了subtask。。。myh:你们乖乖写正解吧
(正解代码交回去反而更慢了QAQ)
题意:
Description
Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的。
接下来会发生q个操作,操作有两种形式:
“1 P”,Bob往自己的集合里添加了一个字符串P。
“2 x”,Alice询问Bob,集合T中有多少个字符串包含串S_x。(我们称串A包含串B,当且仅当B是A的子串)
Bob遇到了困难,需要你的帮助。
Input
第1行,一个数n;
接下来n行,每行一个字符串表示S_i;
下一行,一个数q;
接下来q行,每行一个操作,格式见题目描述。
1 <= n,q <= 100000;
Alice和Bob拥有的字符串长度之和各自都不会超过 2000000;
字符串都由小写英文字母组成。
Output
对于每一个Alice的询问,帮Bob输出答案
题解:
先对S建出AC自动机;
暴力就是每次加入一个T就对所有经过的节点沿着fail指针暴力跳然后修改,但这样会被构造卡成$O(n^2)$的;
正解就是建出fail树,然后每次修改就是把几条树链的并的节点全部加一,那么排序一下,在每个节点处加一,然后在相邻节点减一(注意去重且不包括第一个)即可;
使用树状数组解决。
听说倍增LCA会被卡?实测并不会。。。
代码:
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<vector>
6 #include<cmath>
7 #include<queue>
8 #define inf 2147483647
9 #define eps 1e-9
10 #define lb(x) (x&-x)
11 using namespace std;
12 typedef long long ll;
13 struct node{
14 int son[26],fail;
15 node(){
16 memset(son,0,sizeof(son));
17 fail=0;
18 }
19 }t[2000001];
20 struct edge{
21 int v,next;
22 }a[2000001];
23 int n,Q,x,y,cnt=0,tot=0,tim=0,tr[5000001],ed[2000001],head[2000001],in[2000001],out[2000001],nmd[2000001],ans[2000001],fa[2000001][22],dep[2000001];
24 char s[1000001];
25 void add(int u,int v){
26 a[++tot].v=v;
27 a[tot].next=head[u];
28 head[u]=tot;
29 }
30 void _add(int u,int x){
31 for(;u<=cnt+1;u+=lb(u)){
32 tr[u]+=x;
33 }
34 }
35 int query(int u){
36 int ret=0;
37 for(;u;u-=lb(u)){
38 ret+=tr[u];
39 }
40 return ret;
41 }
42 void ins(char s[],int x){
43 int len=strlen(s),now=0;
44 for(int i=0;i<len;i++){
45 if(!t[now].son[s[i]-'a'])t[now].son[s[i]-'a']=++cnt;
46 now=t[now].son[s[i]-'a'];
47 }
48 ed[x]=now+1;
49 }
50 void AC(){
51 queue<int>q;
52 for(int i=0;i<26;i++){
53 if(t[0].son[i]){
54 add(1,t[0].son[i]+1);
55 t[t[0].son[i]].fail=0;
56 q.push(t[0].son[i]);
57 }
58 }
59 while(!q.empty()){
60 int u=q.front();
61 q.pop();
62 for(int i=0;i<26;i++){
63 if(t[u].son[i]){
64 t[t[u].son[i]].fail=t[t[u].fail].son[i];
65 add(t[t[u].son[i]].fail+1,t[u].son[i]+1);
66 q.push(t[u].son[i]);
67 }else t[u].son[i]=t[t[u].fail].son[i];
68 }
69 }
70 }
71 void dfs(int u,int ff,int dpt){
72 in[u]=++tim;
73 nmd[tim]=u;
74 dep[u]=dpt;
75 fa[u][0]=ff;
76 for(int i=1;i<=21;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
77 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
78 int v=a[tmp].v;
79 dfs(v,u,dpt+1);
80 }
81 out[u]=tim;
82 }
83 int lca(int u,int v){
84 if(dep[u]<dep[v])swap(u,v);
85 int l=dep[u]-dep[v];
86 for(int i=21;i>=0;i--){
87 if((1<<i)&l){
88 u=fa[u][i];
89 }
90 }
91 if(u==v)return u;
92 for(int i=21;i>=0;i--){
93 if(fa[u][i]!=fa[v][i]){
94 u=fa[u][i],v=fa[v][i];
95 }
96 }
97 return fa[u][0];
98 }
99 void work(char s[]){
100 int len=strlen(s),now=0;
101 vector<int>p;
102 for(int i=0;i<len;i++){
103 now=t[now].son[s[i]-'a'];
104 p.push_back(in[now+1]);
105 }
106 sort(p.begin(),p.end());
107 p.erase(unique(p.begin(),p.end()),p.end());
108 for(int i=0,ii=p.size();i<ii;i++){
109 _add(p[i],1);
110 if(i)_add(in[lca(nmd[p[i]],nmd[p[i-1]])],-1);
111 }
112 }
113 int main(){
114 memset(head,-1,sizeof(head));
115 scanf("%d%d",&n,&Q);
116 for(int i=1;i<=n;i++){
117 scanf("%s",s);
118 ins(s,i);
119 }
120 AC();
121 dfs(1,0,1);
122 scanf("%d",&Q);
123 for(int q=1;q<=Q;q++){
124 scanf("%d",&x);
125 if(x==1){
126 scanf("%s",s);
127 work(s);
128 }else{
129 scanf("%d",&y);
130 //printf("%d %d %d\n",ed[y],in[ed[y]],out[ed[y]]);
131 printf("%d\n",query(out[ed[y]])-query(in[ed[y]]-1));
132 }
133 }
134 return 0;
135 }