题意:给出10000个模式串和一个长度为100000的匹配串,有两种操作:
1.查询匹配串的子串[L,R]是否存在于模式串中
2.修改匹配串某个位置的字符
解法:由于RK函数满足区间加法啊,因此可以用线段树动态维护和查询某个子串的hash值,得到子串的hash值,剩下的就是普通的rk了。
将所有模式串的hash值放入map中,对于hash值相同的模式串使用链表串联起来,当获取某个子串的hash值时 ,首先在map中查找是否存在,若存在和此hash值链表上的模式串一一比较。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.TreeMap;
public class FZU2045ac {
long mod = 100000007;
int maxn = 100010;
long pow(long x, int p) {
long ans = 1;
while (p > 0) {
if ((p & 1) == 1)
ans = (ans * x) % mod;
p >>= 1;
x = (x * x) % mod;
}
return ans;
}
class SegTree {
class node {
int left, right;
long hash;
node(int l, int r) {
left = l;
right = r;
}
int length() {
return right - left + 1;
}
int mid() {
return (left + right) >> 1;
}
}
node tree[] = new node[maxn << 2];
void init(int idx, int l, int r, int arr[]) {
tree[idx] = new node(l, r);
if (l == r) {
tree[idx].hash = arr[r];
return;
}
int m = tree[idx].mid();
init(idx << 1, l, m, arr);
init(idx << 1 | 1, m + 1,r, arr);
pushup(idx);
}
void pushup(int idx) {
if (tree[idx].left == tree[idx].right)
return;
tree[idx].hash = (tree[idx<<1].hash
* pow(26, tree[idx<<1|1].length())+tree[idx<< 1|1].hash)
% mod;
}
long query(int idx, int left, int right) {
if (tree[idx].left==left&&tree[idx].right== right)
return tree[idx].hash;
int m = tree[idx].mid();
if (right<=m)
return query(idx << 1, left, right);
if (left>m)
return query(idx << 1 | 1, left, right);
long x = query(idx << 1, left, m);
long y = query(idx << 1 | 1, m + 1, right);
return (x*pow(26,right-m)+y) % mod;
}
void update(int idx, int pos, long val) {
if (tree[idx].left == pos && tree[idx].right == pos) {
tree[idx].hash = val;
return;
}
int m = tree[idx].mid();
if (m >= pos)
update(idx<<1,pos,val);
else
update(idx<<1|1,pos,val);
pushup(idx);
}
}
String ss[] = new String[10010];
int nxt[] = new int[10010], pre[] = new int[10010];
TreeMap<Long, Integer> mp = new TreeMap<Long, Integer>();
void build() throws IOException {
int n = nextInt();
Arrays.fill(nxt, -1);
Arrays.fill(pre, -1);
mp.clear();
for (int i = 1; i <= n; i++) {
ss[i] = next();
int len = ss[i].length();
long hash = 0;
for (int j = 0; j < len; j++)
hash = (hash * 26 + (ss[i].charAt(j) - 'a')) % mod;
if (mp.containsKey(hash)) {
int temp = mp.get(hash);
pre[i] = temp;
nxt[temp] = i;
}
mp.put(hash, i);
}
}
boolean test(int l, int r) {
long hash = st.query(1, l, r);
if (!mp.containsKey(hash))
return false;
int p = mp.get(hash);
while (pre[p] != -1)
p = pre[p];
while (p != -1) {
if (r - l + 1 == ss[p].length()){
boolean flag = true;
for (int i = 0; i < r - l + 1; i++)
if (ss[p].charAt(i) - 'a' != arr[l + i]) {
flag = false;
break;
}
if (flag)
return true;
}
p = nxt[p];
}
return false;
}
int arr[] = new int[maxn];
SegTree st = new SegTree();
void run() throws IOException {
int cas = nextInt();
for (int c = 1; c <= cas; c++) {
System.out.println("Case #"+c+":");
build();
String s = next();
int cnt = s.length();
for (int i = 1; i <= cnt; i++)
arr[i] = s.charAt(i - 1) - 'a';
st.init(1, 1, cnt, arr);
int m = nextInt();
while (m-- > 0) {
String op = next();
if (op.charAt(0) == 'Q')
if (test(nextInt()+1, nextInt()+1))
System.out.println("Yes");
else
System.out.println("No");
else {
int p = nextInt()+1;
int val = next().charAt(0) - 'a';
st.update(1, p, val);
arr[p] = val;
}
}
}
}
StreamTokenizer in = new StreamTokenizer(new BufferedReader(
new InputStreamReader(System.in)));
int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
String next() throws IOException {
in.nextToken();
return in.sval;
}
public static void main(String[] args) throws IOException {
new FZU2045ac().run();
}
}