【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 }
posted @ 2018-10-24 21:42  DCDCBigBig  阅读(156)  评论(0编辑  收藏  举报