1. 程式人生 > >[BZOJ2434]阿貍的打字機

[BZOJ2434]阿貍的打字機

復雜度 content scanf val return queue led 打字機 i++

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

aPaPBbP

3

1 2

1 3

2 3

Sample Output

2

1

0

HINT

1<=N<=10^5


1<=M<=10^5
輸入總長<=10^5

Source

Trie

其實不是很難。

首先我們畫畫圖很容易想到的就是在fail樹上求子樹和,然後單點暴力修改每個串,這樣就是70分。

然後之所以只有70分,是因為有的點被許多串包含所以被修改多次。

如果我們能讓每個點只被修改一次,復雜度就正確了。

其實也不難,我們按建trie的順序dfs,這樣每個點就只會被修改一次了

代碼:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<queue>
  5 #include<algorithm>
  6 #define M 100010
  7
#define ls node*2 8 #define rs node*2+1 9 using namespace std; 10 struct point{ 11 int to,next; 12 }e[M<<1]; 13 struct Ask{ 14 int x,y,id,ans; 15 }ask[M]; 16 17 int n,num,dfn,cnt,Num,tot; 18 int head[M],in[M],out[M]; 19 int end[M],fail[M],fa[M],ch[M][26]; 20 int val[M<<2]; 21 char s[M]; 22 23 void add(int from,int to) 24 { 25 e[++num].next=head[from]; 26 e[num].to=to; 27 head[from]=num; 28 } 29 void dfs(int x) 30 { 31 in[x]=++dfn; 32 for(int i=head[x];i;i=e[i].next) 33 { 34 int to=e[i].to; 35 dfs(to); 36 } 37 out[x]=dfn; 38 } 39 40 void build(string s) 41 { 42 int now=0,len=s.length(); 43 for(int i=0;i<len;i++) 44 { 45 int u=s[i]-a; 46 if(s[i]==P) end[++Num]=now; 47 else if(s[i]==B) now=fa[now]; 48 else 49 { 50 if(!ch[now][u]) 51 { 52 ch[now][u]=++cnt; 53 fa[cnt]=now; 54 } 55 now=ch[now][u]; 56 } 57 } 58 } 59 void build_fail() 60 { 61 queue<int>q; 62 for(int i=0;i<26;i++) 63 if(ch[0][i]) 64 q.push(ch[0][i]); 65 while(!q.empty()) 66 { 67 int u=q.front(); q.pop(); 68 for(int i=0;i<26;i++) 69 { 70 if(ch[u][i]) 71 { 72 fail[ch[u][i]]=ch[fail[u]][i]; 73 q.push(ch[u][i]); 74 } 75 else ch[u][i]=ch[fail[u]][i]; 76 } 77 } 78 } 79 80 int cmp1(Ask x1,Ask x2) {return x1.y<x2.y;} 81 int cmp2(Ask x1,Ask x2) {return x1.id<x2.id;} 82 83 void update(int node) {val[node]=val[ls]+val[rs];} 84 void insert(int node,int l,int r,int k,int v) 85 { 86 if(l==r) 87 { 88 val[node]+=v; 89 return; 90 } 91 int mid=(l+r)/2; 92 if(k<=mid) insert(ls,l,mid,k,v); 93 else insert(rs,mid+1,r,k,v); 94 update(node); 95 } 96 int query(int node,int l,int r,int l1,int r1) 97 { 98 if(l1<=l&&r1>=r) return val[node]; 99 if(l1>r||r1<l) return 0; 100 int mid=(l+r)/2; 101 return query(ls,l,mid,l1,r1)+query(rs,mid+1,r,l1,r1); 102 } 103 104 int main() 105 { 106 scanf("%s",s); 107 build(s); 108 build_fail(); 109 for(int i=1;i<=cnt;i++) add(fail[i],i); 110 dfs(0); 111 scanf("%d",&n); 112 for(int i=1;i<=n;i++) 113 { 114 scanf("%d%d",&ask[i].x,&ask[i].y); 115 ask[i].id=i; 116 } 117 sort(ask+1,ask+1+n,cmp1); 118 int len=strlen(s),p=1,now=0; 119 for(int i=0;i<len;i++) 120 { 121 if(s[i]==P) 122 { 123 tot++; 124 while(ask[p].y==tot&&p<=n) 125 { 126 int x=ask[p].x; 127 ask[p].ans=query(1,1,len,in[end[x]],out[end[x]]); 128 p++; 129 } 130 } 131 else if(s[i]==B) 132 { 133 insert(1,1,len,in[now],-1); 134 now=fa[now]; 135 } 136 else 137 { 138 now=ch[now][s[i]-a]; 139 insert(1,1,len,in[now],1); 140 } 141 } 142 sort(ask+1,ask+1+n,cmp2); 143 for(int i=1;i<=n;i++) printf("%d\n",ask[i].ans); 144 return 0; 145 }

[BZOJ2434]阿貍的打字機