非常に簡単な質問、交流自動機別のLENでこのノードが可能ではないですが、失敗する危険があるため、ノードのそれぞれが照会する使用の暴力ホップの中に失敗する必要があり、それぞれの状態を表す長い文字列を維持ノードは、直接的な休憩を見つけます
速いの配列に続いて差分統計カバレッジ
使用して 名前空間はstdを、 #define N 1000005 チャーS [N]、T [N]。 int型N、CNT [N]。 構造体トライ{ INT NXT [N] [ 26 ]、失敗[N]、エンド[N]、レン[N]。 int型の根、L。 int型newnode(){ memsetの(NXT [L]、 - 1、はsizeof NXT [L])。 端[L] = 0 ; リターン L ++ ; } 無効{INITを() L = 0 。 ルート = newnode()。 } ボイドインサート(チャーBUF []){ int型 LEN = STRLEN(BUF)。 int型になりました= ルート。 以下のために(int型 i = 0 ; iがLEN <; iは++ ){ 場合(NXT [今] [BUF [I] - ' ' ] == - 1 ) NXT [今] [BUF [I] - [ A ' ] = newnode()。 今 = NXT [今] [BUF [I] - ' ' ]。 } 【今】終了 ++;レン[今] = LEN。 } 空のビルド(){ キュー < 整数 > Q; 【ルート】フェイル = ルートと、 以下のために(int型 i = 0 ; iは< 26 ; iは++ ) 場合(NXT [ルート] [I] == - 1 ) NXT [ルート] [I] = 根。 他の{ 失敗[NXT [ルート] [I] = 根。 q.push(NXT [ルート] [I])。 } 一方、(q.size()){ int型 = NOW )q.front(。 q.pop(); 以下のために(int型 i = 0 ; iは< 26 ; iは++ ) 場合(NXT [今] [I] == - 1 ) NXT [今] [I] = NXT [I] [今] [失敗]。 他の{ 失敗[NXT [今] [I] = NXT [I] [今] [失敗]。 q.push(NXT [今] [I])。 } } } 空のクエリ(のchar *のS){ int型になりました= 根を。 INT LEN = STRLEN(S)。 以下のために(int型 i = 0 ; iがLEN <; iは++ ){ もし、(S [i]が< ' ' || sの[I]> ' Z ' ){ 今 =ルート。続け; } 今 = NXT [今] [S [I] - [ A ' ]; int型 P = 今、 一方(P){ IF(完[P]){ // ノードの危険 CNT [Iは+ 1 ] - ; CNT [I -len [P] + 1 ] ++ ; 破ります; } P = 失敗[P]。 } } } }交流; INT のmain(){ int型 TT; CIN >> TT。一方、(tt-- ){ ac.init(); cinを >> N; 以下のために(int型 i = 1 ; iが++; iが<= N ){ scanf関数(" %sの" 、S); ac.insert(S); } ac.build(); 四F; INT LEN = 0 。 getchar関数(); scanf関数(" %の[^ \ n]は%※C " 、S); LEN = strlenを(S)。 以下のために(int型 i = 0 ; iがLEN <; iは++ ){ T [I] =のS [i]は、 もし(S [I]> = ' A ' && S [I] <= ' Z ' ) S [i]が + = ' ' - ' A ' 。 } T [S] = 0 ; 以下のために(int型 i = 0 ; iは= LEN <; iは++)CNTを[I] = 0 ; ac.query(S); 用(int型 i = 1 ; iがLEN <; I ++)はCNT [I] + = CNT [I- 1 ]。 以下のために(int型 I = 0 ; iが<LEN; iが++ ){ 場合(CNT [I]> = 1)のprintf(" * " )。 他のprintf(" %のC " 、T [I])。 } プット("" ); } }