阿狸的打字機 AC自動機 fail樹

2022-09-08 00:12:34 字數 2697 閱讀 3861

bzoj2434: [noi2011]阿狸的打字機

阿狸喜歡收藏各種稀奇古怪的東西,最近他淘到一台老式的打字機。打字機上只有28個按鍵,分別印有26個小寫英文本母和』b』、』p』兩個字母。

經阿狸研究發現,這個打字機是這樣工作的:

l 輸入小寫字母,打字機的乙個凹槽中會加入這個字母(這個字母加在凹槽的最後)

l 按一下印有』b』的按鍵,打字機凹槽中最後乙個字母會消失。

l 按一下印有』p』的按鍵,打字機會在紙上列印出凹槽中現有的所有字母並換行,但凹槽中的字母不會消失。

例如,阿狸輸入apapbbp,紙上被列印的字元如下:

a aa

ab 我們把紙上列印出來的字串從1開始順序編號,一直到n。打字機有乙個非常有趣的功能,在打字機中暗藏乙個帶數字的小鍵盤,在小鍵盤上輸入兩個數(x,y)(其中1≤x,y≤n),打字機會顯示第x個列印的字串在第y個列印的字串**現了多少次。

阿狸發現了這個功能以後很興奮,他想寫個程式完成同樣的功能,你能幫助他麼?

input

輸入的第一行包含乙個字串,按阿狸的輸入順序給出所有阿狸輸入的字元。

第二行包含乙個整數m,表示詢問個數。

接下來m行描述所有由小鍵盤輸入的詢問。其中第i行包含兩個整數x, y,表示第i個詢問為(x, y)。

output

輸出m行,其中第i行包含乙個整數,表示第i個詢問的答案。

sample input

apapbbp

3 1 2

1 3

2 3sample output

2 1

0hint

1<=n<=10^5

1<=m<=10^5

輸入總長<=10^5

分析:網上的題解在我這個zz看來真是晦澀難懂啊,所以只能一點點研究,寫了一篇蒟蒻看的題解(大神勿噴):

這道題需要用到fail樹(實際上是所有fail指標反向構成的樹),簡單解釋一下:

在fail樹中,假使有乙個節點對應的字串為aa,那麼所有以aa為字尾字串都在這個節點的子樹裡。如果串x出現在串y中,那麼串y有幾個字首的字尾以串x結尾,便是出現的次數。而這些y串上的節點都會出現在x的子樹中。

簡單地說串y從某個位置順著fail指標能到達串x尾就增加一次。

我們需要計算的就是以x串最後乙個字元所在的節點為根的子樹中找到包含多少個y串中的節點,把x串最後乙個字元所在節點為根的子樹中的y串上的節點獨立出來,把這些節點的值賦為1,對於所有詢問我們先按照y排一遍序,以後就可以把每乙個y標記完的樹,處理所有對應的(x[i],y)詢問,求乙個區間和(樹狀陣列維護)

這裡寫**片

#include

#include

#include

#include

#include

using

namespace

std;

const

int n=100010;

int n,m,x,y;

char s[n];

int ch[n][26],fa[n],tot=0; //tot:節點數

int word[n]; //word:每個輸出字串對應結尾

int tt=0,fail[n],in[n],out[n],ed=-1; //ed:輔助dfs計數 tt:輔助記錄輸出字串的編號

struct node;

node tree[n*4]; //fail樹

int st[n],totw=0,ans[n]; //ans:記錄答案

struct node2;

node2 qes[n]; //記錄詢問

int c[n]; //樹狀陣列

int comp(const node2 & a,const node2 & b)

void build() //trie樹的構建

if (s[i]=='b')

if (!ch[now][x]) ch[now][x]=++tot,fa[ch[now][x]]=now;

now=ch[now][x];

}return;

}void make() //生成失配指標。順便反向建樹。

fail[ch[r][i]]=ch[fail[r]][i];

q.push(ch[r][i]);}}

for (i=1;i<=tot;i++)

add(fail[i],i);

return;

}void dfs(int t) //對fail樹dfs 根節點是0所以ed初始值是-1,保證t和ed的值能對應的上

out[t]=ed; //在dfs中的終止位置

}//樹狀陣列時建立在dfs序上的,這樣能確保同一顆子樹上的節點在序列中是連續的一段

void change(int bh,int z)

int ask(int bh)

void solve() //把字串重新遍歷一遍

else

if (s[i]=='b')

else}}

return;

}int main()

sort(qes+1,qes+1+m,comp);

solve();

for (int i=1;i<=m;i++)

printf("%d\n",ans[i]);

return

0;}

bzoj 2434 阿狸的打字機 fail樹的性質

如果a串是另b串的字尾,那麼在trie圖上沿著b的fail指標走一定可以走到a串。而a串在b串裡出現多少次就是它是多少個字首的字尾。所以把fail邊反向建樹維護個dfs序就行了。並不是很難。但沒想出來tat 1 include2 include3 include4 include5 define n...

NOI2011阿狸的打字機

阿狸喜歡收藏各種稀奇古怪的東西,最近他淘到一台老式的打字機。打字機上只有28個按鍵,分別印有26個小寫英文本母和 b p 兩個字母。經阿狸研究發現,這個打字機是這樣工作的 l 輸入小寫字母,打字機的乙個凹槽中會加入這個字母 這個字母加在凹槽的最後 l 按一下印有 b 的按鍵,打字機凹槽中最後乙個字母...

NOI2011 阿狸的打字機

阿狸喜歡收藏各種稀奇古怪的東西,最近他淘到一台老式的打字機。打字機上只有28個按鍵,分別印有 26個小寫英文本母和 b p 兩個字母。經阿狸研究發現,這個打字機是這樣工作的 輸入小寫字母,打字機的乙個凹槽中會加入這個字母 按 p 前凹槽中至少有乙個字母 按一下印有 b 的按鍵,打字機凹槽中最後乙個字...