BZOJ3881 Divljak

解:对被包含的那些串建AC自动机。

每次加一个串,就在AC自动机上面跑,可知能够跑到一些节点。

这些节点都是一些前缀的形式,我们跳fail树就是跳后缀,这样就能够得到所有能匹配的子串。

我们分别对AC自动机中的每个串计算答案。

就是要求一些节点到根路径的并集,并对其权值 + 1。查询就查对应节点。

然后有个trick就是lca处 - 1,节点处 + 1,然后求子树和。、

 

  1 #include <bits/stdc++.h>
  2 
  3 const int N = 100010, M = 2000010;
  4 
  5 struct Edge {
  6     int nex, v;
  7 }edge[M]; int tp;
  8 
  9 int tr[M][26], fail[M], tot = 1, n, ed[N];
 10 std::queue<int> Q;
 11 char str[N];
 12 int e[M], pos[M], siz[M], num, ST[M << 1][22], d[M], stk[M], pw[M << 1], top, pos2[M << 1], num2;
 13 
 14 inline void add(int x, int y) {
 15     tp++;
 16     edge[tp].v = y;
 17     edge[tp].nex = e[x];
 18     e[x] = tp;
 19     return;
 20 }
 21 
 22 void DFS(int x) {
 23     pos[x] = ++num;
 24     pos2[x] = ++num2;
 25     ST[num2][0] = x;
 26     siz[x] = 1;
 27     for(int i = e[x]; i; i = edge[i].nex) {
 28         int y = edge[i].v;
 29         d[y] = d[x] + 1;
 30         DFS(y);
 31         ST[++num2][0] = x;
 32         siz[x] += siz[y];
 33     }
 34     return;
 35 }
 36 
 37 inline void prework() {
 38     for(int i = 2; i <= num2; i++) {
 39         pw[i] = pw[i >> 1] + 1;
 40     }
 41     for(int j = 1; j <= pw[num2]; j++) {
 42         for(int i = 1; i + (1 << j) - 1 <= num2; i++) {
 43             if(d[ST[i][j - 1]] < d[ST[i + (1 << (j - 1))][j - 1]])
 44                 ST[i][j] = ST[i][j - 1];
 45             else
 46                 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
 47         }
 48     }
 49     /*for(int j = 0; j <= pw[num2]; j++) {
 50         printf("j = %d : ", j);
 51         for(int i = 1; i + (1 << j) - 1 <= num2; i++) {
 52             printf("%d ", ST[i][j]);
 53         }
 54         puts("");
 55     }*/
 56     return;
 57 }
 58 
 59 inline bool cmp(const int &a, const int &b) {
 60     return pos[a] < pos[b];
 61 }
 62 
 63 inline int lca(int x, int y) {
 64     //printf("lca : %d %d = ", x, y);
 65     x = pos2[x]; y = pos2[y];
 66     if(x > y) std::swap(x, y);
 67     int t = pw[y - x + 1];
 68     if(d[ST[x][t]] < d[ST[y - (1 << t) + 1][t]])
 69         return ST[x][t];
 70         //{ printf("%d \n", ST[x][t]); return ST[x][t]; }
 71     else
 72         return ST[y - (1 << t) + 1][t];
 73         //{ printf("%d \n", ST[y - (1 << t) + 1][t]); return ST[y - (1 << t) + 1][t]; }
 74 }
 75 
 76 namespace ta {
 77     int ta[M];
 78     inline void add(int x, int v) {
 79         for(int i = x; i <= tot; i += i & (-i)) {
 80             ta[i] += v;
 81         }
 82         return;
 83     }
 84     inline int getSum(int x) {
 85         int ans = 0;
 86         for(int i = x; i >= 1; i -= i & (-i)) {
 87             ans += ta[i];
 88         }
 89         return ans;
 90     }
 91     inline int ask(int l, int r) {
 92         return getSum(r) - getSum(l - 1);
 93     }
 94 }
 95 
 96 inline void insert(int id) {
 97     int n = strlen(str), p = 1;
 98     for(int i = 0; i < n; i++) {
 99         int f = str[i] - 'a';
100         if(!tr[p][f]) {
101             tr[p][f] = ++tot;
102         }
103         p = tr[p][f];
104     }
105     ed[id] = p;
106     return;
107 }
108 
109 inline void BFS() {
110     Q.push(1);
111     fail[1] = 1;
112     while(!Q.empty()) {
113         int x = Q.front();
114         Q.pop();
115         for(int f = 0; f < 26; f++) {
116             if(!tr[x][f]) continue;
117             int y = tr[x][f], j = fail[x];
118             while(j != 1 && !tr[j][f]) {
119                 j = fail[j];
120             }
121             if(x != 1 && tr[j][f]) {
122                 j = tr[j][f];
123             }
124             fail[y] = j;
125             Q.push(y);
126         }
127     }
128     return;
129 }
130 
131 inline void add() {
132     int n = strlen(str), p = 1;
133     top = 0;
134     for(int i = 0; i < n; i++) {
135         int f = (str[i]) - 'a';
136         while(p != 1 && !tr[p][f]) p = fail[p];
137         if(tr[p][f]) p = tr[p][f];
138         if(p > 1) stk[++top] = p;
139     }
140     if(!top) return;
141     std::sort(stk + 1, stk + top + 1, cmp);
142     top = std::unique(stk + 1, stk + top + 1) - stk - 1;
143     for(int i = 1; i <= top; i++) {
144         ta::add(pos[stk[i]], 1);
145         if(i < top) {
146             int z = lca(stk[i], stk[i + 1]);
147             ta::add(pos[z], -1);
148         }
149     }
150     return;
151 }
152 
153 inline int ask(int x) {
154     return ta::ask(pos[x], pos[x] + siz[x] - 1);
155 }
156 
157 int main() {
158     int m;
159     scanf("%d", &n);
160     for(int i = 1; i <= n; i++) {
161         scanf("%s", str);
162         insert(i);
163     }
164     BFS();
165     ///
166     for(int i = 2; i <= tot; i++) {
167         add(fail[i], i);
168         //printf("add %d %d \n", fail[i], i);
169     }
170     d[1] = 1;
171     DFS(1);
172     prework();
173 
174     scanf("%d", &m);
175     for(int i = 1, f, x; i <= m; i++) {
176         scanf("%d", &f);
177         if(f == 1) {
178             scanf("%s", str);
179             add();
180         }
181         else {
182             scanf("%d", &x);
183             printf("%d\n", ask(ed[x]));
184         }
185     }
186     return 0;
187 }
MLE代码

 

posted @ 2019-03-08 14:38  huyufeifei  阅读(244)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

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