AC自動機 NOI2011 阿狸的打字機
阿新 • • 發佈:2019-01-02
AC自動機上 根據fail指標 暴力跳有40分
所以我們可以考慮這麼做
對於x和y串 顯然若y上的每個節點可以通過fail跳到x的尾節點 那答案就是個數和
在y節點上打標記,
然後我們把fail指標反向 我們可以發現變成了求x尾節點的子樹和
子樹和可以通過dfs對映到陣列上記錄一下每個節點dfs訪問到的時間和離開的時間 可以表示這棵樹的範圍
然後用樹狀陣列維護我們的求和過程
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&(-x))
#define mp(a,b) make_pair(a,b)
#define pb push_back
typedef pair<int,int> Pair;
vector<int> G[102000];
int ans[102000];
int in[1020000];
int out[1020000];
int tree[102000];
int m;
int cnt;
//樹狀陣列不解釋
int getsum(int x){
int ret = 0;
for(int i=x;i;i-=lowbit(i)){
ret+=tree[i];
}
return ret;
}
void update(int x,int val){
for(int i=x;i<= cnt;i+=lowbit(i)){
tree[i]+=val;
}
}
//求出每個節點的DFS序
void dfs(int x){
in[x]=++cnt;
for(int i=0;i<G[x].size();++i){
int to = G[x][i];
dfs(to);
}
out[x]=cnt;
}
struct node{
int x,y,id;
}q[102000];
struct Trie{
int nxt[100010][26],fail[100010],end[100010],fa[101000],f[102000];
string s;
int root,L,n;
int newnode (){
for(int i=0;i<26;++i){
nxt[L][i]=-1;
}
end[L++]=0;
return L-1;
}
void init(){
L=0;
root=newnode();
}
void insert(){
int now = 0;
cin>>s;
int len = s.size();
for(int i=0;i<len;++i){
if(s[i]=='P') f[++n] = now;//新增一串 記錄末節點位置
else if(s[i]=='B') now = fa[now];//跳到父親節點
else{
if(nxt[now][s[i]-'a']==-1){
nxt[now][s[i]-'a']=newnode();
}
fa[nxt[now][s[i]-'a']] = now;//記錄父親節點
now = nxt[now][s[i]-'a'];
}
}
}
void build(){
queue<int> Q;
fail[root] = root;
for(int i=0;i<26;++i){
if(nxt[root][i] == -1){
nxt[root][i] = root;
}
else{
fail[nxt[root][i]] = root;
Q.push(nxt[root][i]);
}
}
while(!Q.empty()){
int now = Q.front();
Q.pop();
for(int i=0;i<26;++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]);
}
}
}
//每個fail指標反向
for(int i=1;i<=L;i++){
G[fail[i]].pb(i);
}
}
void solve(){
int now = 0;
int id = 1;
n=0;
for(int i=0;i<s.size();++i){
if(s[i]=='P'){
n++;
while(q[id].y==n&&id<=m){//始終是第二個串 可以省去很多不必要的時間
int t = f[q[id].x];//第一個串的終點
ans[q[id].id]=getsum(out[t])-getsum(in[t]-1);
++id;
}
}
else if(s[i]=='B'){
update(in[now],-1);
now = fa[now];
}
else{
now = nxt[now][s[i]-'a'];
update(in[now],1);
}
}
}
}ac;
bool cmp(node a,node b){
return a.y<b.y;
}
int main(){
ac.init();
ac.insert();
ac.build();
dfs(0);
cin>>m;
for(int i=1;i<=m;++i){
cin>>q[i].x>>q[i].y;
q[i].id = i;
}
sort(q+1,q+1+m,cmp);
ac.solve();
for(int i=1;i<=m;++i) cout<<ans[i]<<endl;
return 0;
}