【bzoj 2434】【codevs 1946】[Noi2011]阿狸的打字机(AC自动机)
2434: [Noi2011]阿貍的打字機(jī)
Time Limit:?10 Sec??Memory Limit:?256 MBSubmit:?2477??Solved:?1382
[Submit][Status][Discuss]
Description
?阿貍喜歡收藏各種稀奇古怪的東西,最近他淘到一臺(tái)老式的打字機(jī)。打字機(jī)上只有28個(gè)按鍵,分別印有26個(gè)小寫(xiě)英文字母和'B'、'P'兩個(gè)字母。
經(jīng)阿貍研究發(fā)現(xiàn),這個(gè)打字機(jī)是這樣工作的:
l 輸入小寫(xiě)字母,打字機(jī)的一個(gè)凹槽中會(huì)加入這個(gè)字母(這個(gè)字母加在凹槽的最后)。
l 按一下印有'B'的按鍵,打字機(jī)凹槽中最后一個(gè)字母會(huì)消失。
l 按一下印有'P'的按鍵,打字機(jī)會(huì)在紙上打印出凹槽中現(xiàn)有的所有字母并換行,但凹槽中的字母不會(huì)消失。
例如,阿貍輸入aPaPBbP,紙上被打印的字符如下:
a
aa
ab
我們把紙上打印出來(lái)的字符串從1開(kāi)始順序編號(hào),一直到n。打字機(jī)有一個(gè)非常有趣的功能,在打字機(jī)中暗藏一個(gè)帶數(shù)字的小鍵盤(pán),在小鍵盤(pán)上輸入兩個(gè)數(shù)(x,y)(其中1≤x,y≤n),打字機(jī)會(huì)顯示第x個(gè)打印的字符串在第y個(gè)打印的字符串中出現(xiàn)了多少次。
阿貍發(fā)現(xiàn)了這個(gè)功能以后很興奮,他想寫(xiě)個(gè)程序完成同樣的功能,你能幫助他么?
Input
?輸入的第一行包含一個(gè)字符串,按阿貍的輸入順序給出所有阿貍輸入的字符。
第二行包含一個(gè)整數(shù)m,表示詢(xún)問(wèn)個(gè)數(shù)。
接下來(lái)m行描述所有由小鍵盤(pán)輸入的詢(xún)問(wèn)。其中第i行包含兩個(gè)整數(shù)x, y,表示第i個(gè)詢(xún)問(wèn)為(x, y)。
Output
?輸出m行,其中第i行包含一個(gè)整數(shù),表示第i個(gè)詢(xún)問(wèn)的答案。
Sample Input
aPaPBbP3
1 2
1 3
2 3
Sample Output
21
0
HINT
?1<=N<=10^5
1<=M<=10^5
輸入總長(zhǎng)<=10^5
Source
Trie
[Submit][Status][Discuss]【題解】【AC自動(dòng)機(jī)+樹(shù)狀數(shù)組】
【首先將整個(gè)大串建trie樹(shù)(P、B不能算進(jìn)去,遇到要特判,遇到P要將記錄每個(gè)單詞的數(shù)組更新;遇到B要記錄當(dāng)前點(diǎn)的父節(jié)點(diǎn),以備后面刪除時(shí)往回跳),再建fail樹(shù),根據(jù)fail樹(shù)神奇的特性,將查詢(xún)自動(dòng)機(jī)上root-y的每一個(gè)結(jié)點(diǎn),沿著fail指針是否會(huì)走到x的結(jié)尾點(diǎn),變?yōu)椴樵?xún)自動(dòng)機(jī)上root-y的所有結(jié)點(diǎn)中,有多少個(gè)在x的子樹(shù)中。按照f(shuō)ail樹(shù)跑一遍dfs序。 ?然后將詢(xún)問(wèn)離線,按y排序,每次走到一個(gè)等于y的位置就查詢(xún),用樹(shù)狀數(shù)組維護(hù)】
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; char s[100010]; struct question{int num,x,y; }ask[100010]; int nxt[100010][30],fail[100010],fa[100010],record[100010],num,sz; int a[200010],next[200010],p[100010],tot; int in[100010],out[100010],tp; int tree[200010],ans[100010]; int m,len,cnt;inline int tmp(question a,question b) {return a.y<b.y; } inline void add(int x,int y) {++tot; next[tot]=p[x]; a[tot]=y; p[x]=tot;++tot; next[tot]=p[y]; a[tot]=x; p[y]=tot; }void dfs(int now,int father) {in[now]=++tp;int u=p[now];while (u!=0){int v=a[u];if (v!=father) dfs(v,now);u=next[u];}out[now]=tp;return; }inline void trie() {int now=0;for (int i=0;i<len;++i){if (s[i]>='a'&&s[i]<='z'){int x=s[i]-'a';if (!nxt[now][x]) nxt[now][x]=++sz;fa[nxt[now][x]]=now;now=nxt[now][x];}if (s[i]=='P') record[++num]=now;if (s[i]=='B') now=fa[now];} } inline void make_fail() {queue<int>que;for (int i=0;i<26;++i)if (nxt[0][i]) add(0,nxt[0][i]),que.push(nxt[0][i]);while (!que.empty()){int now=que.front(); que.pop();for (int i=0;i<26;++i){int ch=nxt[now][i];if (!ch){nxt[now][i]=nxt[fail[now]][i]; continue;}int x=nxt[now][i];fail[x]=nxt[fail[now]][i];add(x,fail[x]);que.push(x);}} }inline void init(int x,int val) {for (int i=x;i<=tp;i+=i&(-i))tree[i]+=val; } inline int ask1(int x) {int sum=0;for (int i=x;i>=1;i-=i&(-i))sum+=tree[i];return sum; } int main() {int i,now,k;scanf("%s",s);len=strlen(s);trie();make_fail();dfs(0,-1);scanf("%d",&m);for (i=1;i<=m;++i)scanf("%d%d",&ask[i].x,&ask[i].y),ask[i].num=i;sort(ask+1,ask+m+1,tmp);now=0;k=1;for (i=0;i<len;++i){if (s[i]>='a'&&s[i]<='z'){int x=s[i]-'a';now=nxt[now][x];init(in[now],1);}if (s[i]=='B'){init(in[now],-1);now=fa[now];}if (s[i]=='P'){++cnt;if (cnt==ask[k].y)for (int j=k;ask[j].y==cnt;++j){int ans1=ask1(in[record[ask[j].x]]-1);int ans2=ask1(out[record[ask[j].x]]);ans[ask[j].num]=ans2-ans1;k=j+1;}}}for (i=1;i<=m;++i)printf("%d\n",ans[i]);return 0; }
轉(zhuǎn)載于:https://www.cnblogs.com/lris-searching/p/9402977.html
總結(jié)
以上是生活随笔為你收集整理的【bzoj 2434】【codevs 1946】[Noi2011]阿狸的打字机(AC自动机)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: url参数中有+、空格、=、%、、#等特
- 下一篇: Maximum sum(poj 2479