2019牛客国庆集训派对day6 I - Substring Query

题意:

给定一个长为 n 的串 s,再有 q 个操作,① i, c i c_i ,修改 s[ i ] = c i c_i ;② 0, p i p_i ,询问长为 l i l_i 的串 p i p_i 在 串 s 中出现的次数。(n, l i \sum{li} <= 5e4, q <= 1e5)

链接:

https://ac.nowcoder.com/acm/contest/1111/I

解题思路:

bitset 大法好! 先分类讨论,当 l i l_i > n \sqrt{n} 时,可以用 kmp 直接匹配,这样的串不超过 n \sqrt{n} 个,这部分 O ( n n ) O(n\sqrt{n}) 。否则,询问串长被限制在 n \sqrt{n} ,注意到单次修改只会影响经过 s i s_i n \sqrt{n} 个串对答案的贡献,如果能在 O ( n ) O(\sqrt{n}) 的时间维护,就做完了。由于主串 s 带修改,考虑离线对匹配串建立 ac 自动机,再将 fail 树建出来。对于单次修改,在 ac 自动机上跑影响答案的 O ( n ) O(\sqrt{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;
}
发布了55 篇原创文章 · 获赞 0 · 访问量 1263

猜你喜欢

转载自blog.csdn.net/weixin_44059127/article/details/102471653