洛谷P2414 阿狸的打字機

題意:以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 }
AC代碼
相關文章
相關標籤/搜索