题意:
题意:给出10000个模式串和一个长度为100000的匹配串,有两种操作:
1.查询匹配串的子串[L,R]是否存在于模式串中
2.修改匹配串某个位置的字符
解析:
将一个字符串看成是一个P进制的数字,那么可以知道每一个字符串都可以被唯一表示( P>256 ,并不考虑高精度)。可是由于字符串的长度比较大,那么我们无法保存如此大的数字。于是使用Hash mod2^64来作为Hash。(的却可能会冲突,可是冲突的概率趋于无穷小)
Hash(s,P)=s[0]∗PLen−1+s[1]∗PLen−2+…+s[Len−1]∗P0mod264
P随便选个素数什么的都可以。
之后假设没有修改操作,那么我们可以与处理出 H[i] 表示 S[0..i] 的Hash
那么为了获得S[l..r]的Hash,我们有:
S[0..r]=s[0]∗Pr+s[1]∗Pr−1+…+s[r]∗P0
S[0..l−1]=s[0]∗Pl−1+s[1]∗Pl−2+…+s[l−1]∗P0
于是
S[l..r]=s[l]∗Pr−l+s[l+1]∗Pr−l−1+…+s[r]∗P0
=S[0..r]–S[0..l−1]∗Pr−l+1
=H[r]–H[l−1]∗Pr−l+1
其中 Pr−l+1 显然直接预处理。
于是查询就可以O(1)
现在需要修改某些字符
于是可以使用一颗线段树来维护
[L..R]维护S[L..R]的Hash,这样更新查询均解决。更新和查询均为O(logN)级别
注意:
query的时候要更改查询的区间,因为这个错误debug了好久。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
#define sigma_size 33
using namespace std;
typedef unsigned long long ll;
const int N = (int)2e6 + 10;
const int maxn = (int)1e5 + 10;
set<ll> mySet;
char str[N];
ll sumv[maxn<<2], H[maxn];
ll idx(char c) { return c - 'a' + 1; }
ll getHash(char *s) {
int len = strlen(s);
ll ret = 0;
for(int i = 0; i < len; i++) {
ret = ret * sigma_size + idx(s[i]);
}
return ret;
}
inline void pushUp(int o, int L, int R) {
int M = (L + R) / 2;
sumv[o] = H[R - M] * sumv[ls] + sumv[rs];
}
void init() {
H[0] = 1;
for(int i = 1; i < maxn; i++) {
H[i] = H[i-1] * sigma_size;
}
}
void build(int o, int L, int R) {
if(L == R) {
sumv[o] = idx(str[L]);
return ;
}
int M = (L + R) / 2;
build(lson);
build(rson);
pushUp(o, L, R);
}
ll query(int o, int L, int R, int ql, int qr) {
if(ql <= L && R <= qr)
return sumv[o];
int M = (L + R) >> 1;
if(qr <= M) return query(lson, ql, qr);
else if(ql > M) return query(rson, ql, qr);
return query(lson, ql, M) * H[qr - M] + query(rson, M+1, qr);
}
void modify(int o, int L, int R, int pos) {
if(L == R) {
sumv[o] = idx(str[pos]);
return ;
}
int M = (L + R) >> 1;
if(pos <= M) modify(lson, pos);
else modify(rson, pos);
pushUp(o, L, R);
}
int n, q;
int main() {
init();
int T, cas = 1;
scanf("%d", &T);
while(T--) {
mySet.clear();
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%s", str);
mySet.insert(getHash(str));
}
scanf("%s", str);
int len = strlen(str);
build(1, 0, len-1);
char oper[5], c[5];
int ql, qr, pos;
printf("Case #%d:\n", cas++);
scanf("%d", &q);
for(int i = 1; i <= q; i++) {
scanf("%s", oper);
if(oper[0] == 'Q') {
scanf("%d%d", &ql, &qr);
ll ret = query(1, 0, len-1, ql, qr);
puts(mySet.count(ret) ? "Yes" : "No");
}else {
scanf("%d%s", &pos, c);
str[pos] = c[0];
modify(1, 0, len-1, pos);
}
}
}
return 0;
}