bzoj 2434 [NOI2011] 阿狸的打字机

题面:

https://www.lydsy.com/JudgeOnline/problem.php?id=2434

 

题解:

建立AC自动机

把fail树拎出来,询问(x,y)就是在root到y的路径上,沿着fail能走到x的点有几个

那么就是fail树上x的子树中有几个root到y路径上的节点

我们遍历fail树,可以得到每个节点的进出时间l,r

然后遍历trie树,进入一个节点就在树状数组上这个节点的l值的位置+1,退出时就-1,当前节点如果是某一个字符串的end时,我们处理所有y是这个字符串的询问:

我们只要看子树里的和就行了,那么就查询l到r的和就是答案

 

Code:

  1 #include<stdio.h>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<algorithm>
  5 #include<vector>
  6 #include<map>
  7 #include<set>
  8 #include<cmath>
  9 #include<iostream>
 10 #include<queue>
 11 #include<string>
 12 using namespace std;
 13 typedef long long ll;
 14 typedef pair<int,int> pii;
 15 typedef long double ld;
 16 typedef unsigned long long ull;
 17 typedef pair<long long,long long> pll;
 18 #define fi first
 19 #define se second
 20 #define pb push_back
 21 #define mp make_pair
 22 #define rep(i,j,k)  for(register int i=(int)(j);i<=(int)(k);i++)
 23 #define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
 24 
 25 ll read(){
 26     ll x=0,f=1;char c=getchar();
 27     while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
 28     while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
 29     return x*f;
 30 }
 31 
 32 const int maxnode=150100;
 33 const int maxn=100100;
 34 
 35 #define lowbit(x) (x&-x)
 36 struct BIT{
 37     int a[maxn*5];
 38     void add(int x,int val){
 39         while(x<=maxn*4){
 40             a[x]+=val;
 41             x+=lowbit(x);
 42         }
 43     }
 44     int ask(int x){
 45         int ret=0;
 46         while(x){ret+=a[x];x-=lowbit(x);}
 47         return ret;
 48     }
 49 } bit;
 50 
 51 vector<pii> q[maxn];
 52 string s;
 53 int l[maxn],r[maxn],tim;
 54 int ans[maxn];
 55 int dy[maxn*4];
 56 int head[maxn*4],to[maxn*8],nxt[maxn*8],cnt;
 57 int nums;
 58 
 59 void addedge(int a,int b){
 60      to[++cnt]=b;nxt[cnt]=head[a];head[a]=cnt;
 61 }
 62 
 63 struct Trie{
 64     int nxt[maxnode][26],fail[maxnode],en[maxnode];
 65     int root,sz;
 66     int fa[maxnode];
 67     int nxt2[maxnode][26];
 68     
 69     int newnode(){
 70         for(int i=0;i<26;i++) nxt[sz][i]=-1;
 71         en[sz]=0;sz++;
 72         return sz-1;
 73     }
 74     void init(){
 75         sz=0;
 76         root=newnode();
 77     }
 78     
 79     void doit(){
 80         getline(cin,s);
 81         int nw=root;
 82         for(int i=0;i<s.size();i++){
 83             if(s[i]=='P') en[nw]=++nums,dy[nums]=nw;
 84             else if(s[i]=='B') nw=fa[nw];
 85             else{
 86                 if(nxt[nw][s[i]-'a']==-1) nxt[nw][s[i]-'a']=newnode();
 87                 fa[nxt[nw][s[i]-'a']]=nw;
 88                 nw=nxt[nw][s[i]-'a'];
 89             }
 90         }
 91     }            
 92     void build(){
 93         for(int i=0;i<sz;i++)
 94             for(int j=0;j<26;j++)
 95                 nxt2[i][j]=nxt[i][j];
 96         queue<int> q;
 97         fail[root]=root;
 98         for(int i=0;i<26;i++)
 99             if(nxt[root][i]==-1) nxt[root][i]=root;
100             else{
101                 fail[nxt[root][i]]=root;
102                 q.push(nxt[root][i]);
103             }
104         while(!q.empty()){
105             int nw=q.front();q.pop();
106             for(int i=0;i<26;i++)
107                 if(nxt[nw][i]==-1) nxt[nw][i]=nxt[fail[nw]][i];
108                 else{
109                     if(nxt[nw][i]==0){
110                         cout<<nw<<endl;
111                         break;
112                     }
113                     fail[nxt[nw][i]]=nxt[fail[nw]][i];
114                     q.push(nxt[nw][i]);
115                 }
116         }
117         for(int i=1;i<sz;i++){
118             int u=i,v=fail[u];
119             addedge(v,u);
120         }
121     }
122     
123     void dfs(int u){
124         bit.add(l[u],1);
125         if(en[u]){
126             for(int i=0;i<q[en[u]].size();i++){
127                 int v=q[en[u]][i].fi;v=dy[v];
128                 int ind=q[en[u]][i].se;
129                 ans[ind]=bit.ask(r[v])-bit.ask(l[v]-1);
130             }
131         }
132         for(int i=0;i<26;i++)
133             if(nxt2[u][i]!=-1) dfs(nxt2[u][i]);
134         bit.add(l[u],-1);
135     }
136 } tr;
137 
138 inline void dfs(int u){
139     l[u]=++tim;
140     r[u]=l[u];
141     for(int i=head[u];i;i=nxt[i]){
142         int v=to[i];
143         dfs(v);
144         r[u]=r[v];
145     }
146 }
147 
148 int main(){
149 //    freopen("2434.in","r",stdin);
150 //    freopen("2434.out","w",stdout);
151     tr.init();
152     tr.doit();
153     tr.build();
154     int m=read();
155     for(int i=1;i<=m;i++){
156         int x=read(),y=read();
157         q[y].pb(mp(x,i));
158     }
159     dfs(0);
160     tr.dfs(0);
161     for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
162     return 0;
163 }
164 
165 /*
166 aPaPBbP
167 3
168 1 2
169 1 3
170 2 3
171 */
View Code

 

Review:

  1. 卡了几个月的问题:输入超时

    我们不能维护一个字符串表示当前打字机内的字符串,然后每次暴力插入,这样就超时了

    我们应该维护一个当前在trie上的节点,然后来回移动

  2. 怎么想:

    其实不难想

    首先肯定上AC自动机,然后询问肯定得离线,那么就是求子树内的和,用dfs序转化成序列上的和是常规套路了

posted @ 2018-08-26 22:46  wawawa8  阅读(165)  评论(0编辑  收藏  举报