题意:
给定一个长为 n 的串 s,再有 q 个操作,① i, c i c_i ci,修改 s[ i ] = c i c_i ci;② 0, p i p_i pi,询问长为 l i l_i li 的串 p i p_i pi 在 串 s 中出现的次数。(n, ∑ l i \sum{li} ∑li <= 5e4, q <= 1e5)
链接:
https://ac.nowcoder.com/acm/contest/1111/I
解题思路:
bitset 大法好! 先分类讨论,当
l
i
l_i
li >
n
\sqrt{n}
n 时,可以用 kmp 直接匹配,这样的串不超过
n
\sqrt{n}
n 个,这部分
O
(
n
n
)
O(n\sqrt{n})
O(nn) 。否则,询问串长被限制在
n
\sqrt{n}
n,注意到单次修改只会影响经过
s
i
s_i
si 的
n
\sqrt{n}
n 个串对答案的贡献,如果能在
O
(
n
)
O(\sqrt{n})
O(n) 的时间维护,就做完了。由于主串 s 带修改,考虑离线对匹配串建立 ac 自动机,再将 fail 树建出来。对于单次修改,在 ac 自动机上跑影响答案的
O
(
n
)
O(\sqrt{n})
O(n) 长的那部分串,相应加减贡献。对于询问,在 dfs 序上分块维护即可。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int maxm = 1e3 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int B = 101;
vector<int> G[maxn];
char s[maxn], ss[maxn], t[maxn];
int nxt[maxn][26], fail[maxn], num[maxn];
int in[maxn], out[maxn], tim;
int id[maxn], li[maxm], ri[maxm], sum[maxm];
int nx[maxn], ans[maxn];
struct Qr{
int x, p; char ch;
} qr[maxn];
int n, q, cnt, tot;
int add(){
mem(nxt[++cnt], 0); fail[cnt] = 0; return cnt;
}
int ins(char *s, int n){
int p = 0;
for(int i = 0; i < n; ++i){
int t = s[i] - 'a';
if(!nxt[p][t]) nxt[p][t] = add();
p = nxt[p][t];
}
return p;
}
void cFail(){
queue<int> q;
for(int i = 0; i < 26; ++i) if(int v = nxt[0][i]) G[0].pb(v), q.push(v);
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = 0; i < 26; ++i){
if(int v = nxt[u][i]){
fail[v] = nxt[fail[u]][i], q.push(v);
if(fail[v] != v) G[fail[v]].pb(v);
}
else nxt[u][i] = nxt[fail[u]][i];
}
}
}
int ac(int p, char *s, int n, int v){
for(int i = 0; i < n; ++i){
int t = s[i] - 'a';
p = nxt[p][t], num[in[p]] += v, sum[id[in[p]]] += v;
}
return p;
}
void dfs(int u){
in[u] = ++tim;
for(int i = 0; i < sz(G[u]); ++i){
int v = G[u][i];
dfs(v);
}
out[u] = tim;
}
void build(){
int len = sqrt(cnt + 1);
for(int i = 1; i <= cnt; ++i) id[i] = (i - 1) / len + 1;
for(int i = 1; i <= id[cnt]; ++i) li[i] = (i - 1) * len + 1, ri[i] = i * len; ri[id[cnt]] = cnt;
for(int i = 1; i <= id[cnt]; ++i) sum[i] = 0;
for(int i = 1; i <= cnt; ++i) num[i] = 0;
}
int query(int l, int r){
int p1 = id[l], p2 = id[r], ret = 0;
if(p1 == p2){
for(int i = l; i <= r; ++i) ret += num[i];
return ret;
}
for(int i = p1 + 1; i < p2; ++i) ret += sum[i];
for(int i = l; i <= ri[p1]; ++i) ret += num[i];
for(int i = li[p2]; i <= r; ++i) ret += num[i];
return ret;
}
void cNext(char *s, int n){
int i = 0, j = -1; nx[0] = -1;
while(i < n){
if(j == -1 || s[i] == s[j]) nx[++i] = ++j;
else j = nx[j];
}
}
int kmp(char *s, int n, char *t, int m){
int ret = 0, i = 0, j = 0;
while(i < n){
if(j == -1 || s[i] == t[j]) ++i, ++j;
else j = nx[j];
if(j == m) ++ret;
}
return ret;
}
void init(){
for(int i = 0; i <= cnt; ++i) G[i].clear();
cnt = -1; add(); tim = -1, tot = 0;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
while(cin >> n >> q){
init();
cin >> s;
for(int i = 0; i <= n; ++i) ss[i] = s[i];
for(int i = 1; i <= q; ++i){
int x; cin >> x >> t; --x;
if(x == -1){
int m = strlen(t);
if(m <= B) qr[i].x = ins(t, strlen(t)), qr[i].p = ++tot;
else qr[i].p = -1, cNext(t, m), ans[++tot] = kmp(ss, n, t, m);
}
else qr[i] = {x, 0, t[0]}, ss[x] = t[0];
}
cFail(); dfs(0);
build(); ac(0, s, n, 1);
for(int i = 1; i <= q; ++i){
int x = qr[i].x, p = qr[i].p;
if(!p){
int l = max(0, x - B + 1), r = min(n - 1, x + B - 1);
int pos = ac(0, s + l, x - l, 0);
ac(pos, s + x, r - x + 1, -1);
s[x] = qr[i].ch;
ac(pos, s + x, r - x + 1, 1);
}
else if(p > 0){
int l = in[x], r = out[x];
ans[p] = query(l, r);
}
}
for(int i = 1; i <= tot; ++i) cout << ans[i] << endl;
}
return 0;
}
bitset 做法:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 5e4 + 5;
const int maxm = 1e5 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
bitset<maxn> bs[26], ret;
char s[maxn], t[maxn];
int n, q;
int main(){
ios::sync_with_stdio(0); cin.tie(0);
while(cin >> n >> q){
cin >> s + 1;
for(int i = 0; i < 26; ++i) bs[i].reset();
for(int i = 1; s[i]; ++i) bs[s[i] - 'a'].set(i);
while(q--){
int x; cin >> x >> t + 1;
if(x){
bs[s[x] - 'a'].reset(x);
s[x] = t[1];
bs[s[x] - 'a'].set(x);
}
else{
ret = bs[t[1] - 'a'];
for(int i = 2; t[i]; ++i){
ret <<= 1;
ret &= bs[t[i] - 'a'];
}
cout << ret.count() << endl;
}
}
}
return 0;
}