2434: [Noi2011]阿貍的打字機
Time Limit:?10 Sec??Memory Limit:?256 MBSubmit:?2477??Solved:?1382
[Submit][Status][Discuss]
Description
?阿貍喜歡收藏各種稀奇古怪的東西,最近他淘到一臺老式的打字機。打字機上只有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
3
1 2
1 3
2 3
Sample Output
1
0
HINT
?1<=N<=10^5
Source
Trie
【題解】【AC自動機+樹狀數組】
【首先將整個大串建trie樹(P、B不能算進去,遇到要特判,遇到P要將記錄每個單詞的數組更新;遇到B要記錄當前點的父節點,以備后面刪除時往回跳),再建fail樹,根據fail樹神奇的特性,將查詢自動機上root-y的每一個結點,沿著fail指針是否會走到x的結尾點,變為查詢自動機上root-y的所有結點中,有多少個在x的子樹中。按照fail樹跑一遍dfs序。 ?然后將詢問離線,按y排序,每次走到一個等于y的位置就查詢,用樹狀數組維護】
#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;
}