題意:以trie的形式給出n個字符串,每次詢問第x個字符串在第y個字符串中出現了幾回。node
解:總串長是n2級別的,因此不能用什麼後綴自動機...數組
[update]能夠建triesam可是不知道trie上的一個節點對應到了sam上的哪幾個節點...感受能夠作...好混亂ide
據說是個AC自動機上DP,而後怎麼想狀態都是n²的,而後看題解發現跟DP沒啥關係...spa
是這樣的:對於x在y中出現的每一次,咱們把它的前面一直補齊,這樣每一個串就對應着y的一個前綴,且這個前綴的一個後綴是x。code
可知,trie上y節點到根的鏈就表明這些前綴。blog
而後要求後綴是x。由於x也在這些串中出現了,因此這些前綴一直跳fail的話必定會跳到x節點。即他們全都在x的fail樹的子樹中。字符串
而後咱們就發現,trie上y到根的路徑上的節點和fail樹上x的子樹的節點的交就是答案。get
一個很樸素的想法就是把這兩棵樹剖出來,就是一個二維數點問題。把主席樹建出來,由於用了樹剖因此每次回答詢問是nlog²n的,能夠作到在線。string
一個高端想法就是離線下來,按照fail樹建DFS序。在trie上DFS,維護trie樹上當前節點到根的路徑權值爲1,別的地方爲0。
it
而後查詢就是當在trie上DFS到y的時候,查詢x在fail樹中的子樹權值和。
這是單點修改,區間查詢。樹狀數組便可。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <stack> 5 #include <queue> 6 #include <vector> 7 8 const int N = 100010; 9 10 struct Edge { 11 int nex, v; 12 }edge[N << 1]; int top; 13 14 struct Node { 15 int x, y, ans; 16 }node[N]; 17 18 int tr[N][26], fail[N], tot = 1; 19 char str[N]; 20 int ed[N], e[N], pos[N], siz[N], num; 21 std::vector<int> v[N]; 22 23 namespace bit { 24 int ta[N]; 25 inline void add(int p) { 26 for(int i = p; i < N; i += i & (-i)) { 27 ta[i]++; 28 } 29 return; 30 } 31 inline void del(int p) { 32 for(int i = p; i < N; i += i & (-i)) { 33 ta[i]--; 34 } 35 return; 36 } 37 inline int getSum(int p) { 38 int ans = 0; 39 for(int i = p; i >= 1; i -= i & (-i)) { 40 ans += ta[i]; 41 } 42 return ans; 43 } 44 inline int ask(int l, int r) { 45 return getSum(r) - getSum(l - 1); 46 } 47 } 48 49 inline void add(int x, int y) { 50 top++; 51 edge[top].v = y; 52 edge[top].nex = e[x]; 53 e[x] = top; 54 return; 55 } 56 57 inline void getAC() { 58 std::stack<int> S; 59 std::queue<int> Q; 60 int n = strlen(str), t = 0, p = 1; 61 for(int i = 0; i < n; i++) { 62 if(str[i] == 'P') { 63 ed[++t] = p; 64 continue; 65 } 66 if(str[i] == 'B') { 67 if(!S.empty()) { 68 p = S.top(); 69 S.pop(); 70 } 71 continue; 72 } 73 int f = str[i] - 'a'; 74 if(!tr[p][f]) { 75 tr[p][f] = ++tot; 76 } 77 S.push(p); 78 p = tr[p][f]; 79 } 80 // getfail 81 fail[1] = 1; 82 Q.push(1); 83 while(!Q.empty()) { 84 int x = Q.front(); 85 Q.pop(); 86 for(int f = 0; f < 26; f++) { 87 if(!tr[x][f]) { 88 continue; 89 } 90 int y = tr[x][f], j = fail[x]; 91 while(!tr[j][f] && j != 1) { 92 j = fail[j]; 93 } 94 if(tr[j][f] && x != 1) { 95 j = tr[j][f]; 96 } 97 fail[y] = j; 98 add(j, y); 99 Q.push(y); 100 } 101 } 102 return; 103 } 104 105 void DFS_1(int x) { 106 pos[x] = ++num; 107 siz[x] = 1; 108 for(int i = e[x]; i; i = edge[i].nex) { 109 int y = edge[i].v; 110 DFS_1(y); 111 siz[x] += siz[y]; 112 } 113 return; 114 } 115 116 void DFS_2(int x) { 117 bit::add(pos[x]); 118 for(int i = 0; i < v[x].size(); i++) { 119 int t = node[v[x][i]].x; 120 node[v[x][i]].ans = bit::ask(pos[ed[t]], pos[ed[t]] + siz[ed[t]] - 1); 121 } 122 for(int i = 0; i < 26; i++) { 123 if(tr[x][i]) { 124 DFS_2(tr[x][i]); 125 } 126 } 127 bit::del(pos[x]); 128 return; 129 } 130 131 int main() { 132 scanf("%s", str); 133 // 134 getAC(); 135 DFS_1(1); 136 int m; 137 scanf("%d", &m); 138 for(int i = 1; i <= m; i++) { 139 scanf("%d%d", &node[i].x, &node[i].y); 140 v[ed[node[i].y]].push_back(i); 141 } 142 143 DFS_2(1); 144 145 for(int i = 1; i <= m; i++) { 146 printf("%d \n", node[i].ans); 147 } 148 return 0; 149 }