给出n个串,m个询问形如: S [ l ] , S [ l + 1 ] . . S [ r ] S[l],S[l+1]..S[r] S[l],S[l+1]..S[r]在 S [ t ] S[t] S[t]中出现的次数之和。 ∑ ∣ s ∣ ≤ 1 0 5 , m ≤ 1 0 5 \sum |s| \leq 10^5,m\leq10^5 ∑∣s∣≤105,m≤105
搞半天都搞不出一个log的
考虑上个根号算法:
所有串建ac自动机,记m为所有串的长度和。
S [ t ] ≥ m S[t]\geq \sqrt m S[t]≥m 的询问,暴力在ac自动机上求出每个串在其中的出现次数并查询。这里是 O ( m m ) O(m\sqrt m) O(mm )
否则,在L-1与R处打两个询问标记。再对整个序列进行扫描,差分求解。
这里是 O ( q m log m + n log m ) O(q\sqrt m \log m+n\log m) O(qm logm+nlogm)
均衡一下大小可以将log放进根号里。
其实第二部分还可以再次分块去掉log
发现一题跟他反过来的547E,这个是可以用类似第二部分的方法一个log的。
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; typedef long long ll; int n, q, tot = 1, c[N][26], fail[N], m; char s[N]; #define lowbit(x) ((x) & -(x)) ll bit[N]; ll query(int x) { ll ret = 0; for (; x; x -= lowbit(x)) ret += bit[x]; return ret; } void change(int x, int v) { for(; x <= tot; x += lowbit(x)) bit[x] += v; } vector<int> tag[N], to[N], g[N]; int dfn[N], R[N], stm; void dfs(int x) { dfn[x] = ++ stm; for(int y : to[x]) dfs(y); R[x] = stm; } void build_ac() { static int Q[N]; int h = 0, t = 0; Q[t = 1] = 1; while (h < t) { int x = Q[++h]; for(int i = 0; i < 26; i++) if (c[x][i]) { Q[++t] = c[x][i]; int k = fail[x]; while(k && c[k][i] == 0) k = fail[k]; if (k) k = c[k][i]; else k = 1; fail[c[x][i]] = k; } } for(int i = 2; i <= tot; i++) to[fail[i]].push_back(i); dfs(1); } ll ans[N]; ll sum[N]; ll cnt[N]; vector<pair<int, pair<int,int>>> qry[N]; vector<pair<int, int>> ask[N]; void get_cnt(int x) { for(int y : to[x]) get_cnt(y), sum[x] += sum[y]; for(int a : tag[x]) cnt[a] += sum[x]; } int main() { freopen("f.in", "r", stdin); cin >> n >> q; int gg = 0; for(int i = 1; i <= n; i++) { scanf("%s", s + 1); m = strlen(s + 1); gg += m; int now = 1; for(int j = 1; j <= m; j++) { int r = s[j] - 'a'; if (c[now][r] == 0) c[now][r] = ++ tot; now = c[now][r]; g[i].push_back(now); } tag[now].push_back(i); } build_ac(); int fj = sqrt(gg); for(int i = 1; i <= q; i++) { int l, r, t; scanf("%d %d %d", &l, &r, &t); if (g[t].size() >= fj) qry[t].push_back(make_pair(i, make_pair(l, r))); else { ask[l - 1].push_back(make_pair(-i, t)); ask[r].push_back(make_pair(i, t)); } } for(int i = 1; i <= n; i++) if (g[i].size() >= fj) { memset(cnt, 0, sizeof cnt); memset(sum, 0, sizeof sum); for(int x : g[i]) sum[x]++; get_cnt(1); for(int i = 1; i <= n; i++) cnt[i] += cnt[i - 1]; for(pair<int,pair<int,int>> a : qry[i]) { ans[a.first] = cnt[a.second.second] - cnt[a.second.first - 1]; } } for(int i = 1; i <= n; i++) { change(dfn[g[i].back()], 1); change(R[g[i].back()] + 1, -1); for(pair<int,int> a : ask[i]) { for(int x : g[a.second]) { ans[abs(a.first)] += (a.first > 0 ? 1 : -1) * query(dfn[x]); } } } for(int i = 1; i <= q; i++) printf("%I64d\n", ans[i]); }