洛谷P2414 阿狸的打字机

题意:以trie的形式给出n个字符串,每次询问第x个字符串在第y个字符串中出现了几次。

解:总串长是n2级别的,所以不能用什么后缀自动机...

[update]可以建triesam但是不知道trie上的一个节点对应到了sam上的哪几个节点...感觉可以做...好混乱

听说是个AC自动机上DP,然后怎么想状态都是n²的,然后看题解发现跟DP没啥关系...

是这样的:对于x在y中出现的每一次,我们把它的前面一直补齐,这样每个串就对应着y的一个前缀,且这个前缀的一个后缀是x。

可知,trie上y节点到根的链就代表这些前缀。

然后要求后缀是x。因为x也在这些串中出现了,所以这些前缀一直跳fail的话一定会跳到x节点。即他们全都在x的fail树的子树中。

然后我们就发现,trie上y到根的路径上的节点和fail树上x的子树的节点的交就是答案。

一个很朴素的想法就是把这两棵树剖出来,就是一个二维数点问题。把主席树建出来,因为用了树剖所以每次回答询问是nlog²n的,可以做到在线。

一个高端想法就是离线下来,按照fail树建DFS序。在trie上DFS,维护trie树上当前节点到根的路径权值为1,别的地方为0。

然后查询就是当在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代码

 

posted @ 2019-01-27 18:50  huyufeifei  阅读(226)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜