AC's String
Time Limit: 30000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Problem Description
You are given some words {Wi}. Then our stupid AC will give you a very long string S. AC is stupid and always wants to know whether one substring from S exists in the given words {Wi} .
For example, S = "abcd", and the given words {Wi} = {"bc", "ad", "dd"}. Then Only S[2..3] = "bc" exists in the given words. (In this problem, the first element of S has the index "0".)
However, this is toooooooooooo easy for acmers ! The stupid and evil AC will now change some letters in S. So could you solve this problem now?
For example, S = "abcd", and the given words {Wi} = {"bc", "ad", "dd"}. Then Only S[2..3] = "bc" exists in the given words. (In this problem, the first element of S has the index "0".)
However, this is toooooooooooo easy for acmers ! The stupid and evil AC will now change some letters in S. So could you solve this problem now?
Input
The first line is one integer T indicates the number of the test cases. (T <=20)
Then for every case, there is one integer n in the first line indicates the number of the given words(The size of the {Wi}) . Then n lines has one string which only has 'a'- 'z'. (1 <= n <= 10000, sigma|Wi| <= 2000000) .
Then one line has one string S, here |S| <= 100000.
Then one integer m, indicating the number of operations. (1 <= m <= 100000)
Then m lines , each line is the operation:
(1)Q L R , tell AC whether the S[L..R] exists in the given strings ;
(2)C X Y , chang S[X] to Y, here Y : 'a'-'z' .
Then for every case, there is one integer n in the first line indicates the number of the given words(The size of the {Wi}) . Then n lines has one string which only has 'a'- 'z'. (1 <= n <= 10000, sigma|Wi| <= 2000000) .
Then one line has one string S, here |S| <= 100000.
Then one integer m, indicating the number of operations. (1 <= m <= 100000)
Then m lines , each line is the operation:
(1)Q L R , tell AC whether the S[L..R] exists in the given strings ;
(2)C X Y , chang S[X] to Y, here Y : 'a'-'z' .
Output
First output “Case #idx:” in a single line, here idx is the case number count from 1.Then for each "Q" operation, output "Yes" if S[L..R] exists in the given strings, otherwise output "No".
Sample Input
1 2 ab ioc ipcad 6 Q 0 2 Q 3 4 C 1 o C 4 b Q 0 2 Q 3 4
Sample Output
Case #1: No No Yes Yes
解题思路:这个题目最开始的想法是把S[l....r]串存入线段树节点中,但是题目给的数据量太大,一下就爆了。。。所以参考了别人的,把这段字符串的哈希值存入。。
诶,,看来线段树的运用相当灵活。。。此外,字符串哈希有一个性质我没想到,所以我一直在想怎么样把每个节点中的哈希值更新。。。感觉这道题又让自己对字符串哈希的理解又深入了一点。。。
我们假设已经知道了S[l....mid]和S[mid+1......r]两个字符串的哈希值(按照我的习惯是逆着算的),我们要求S[l......r]的哈希值。。hash[l......r] = hash[l......mid]+hash[mid+1....r]*p^(mid-l+1),p是质数。。。其实这个性质很容易推理的,只要按照计算哈希值的定义就可以推理了:hash[l.......len-1] = s[len-1]*p^(len-1-l)+s[len-2]*p^(len-1-l+1)+.......+s[l]*p^0。
AC:
#include<cstdio>
#include<cstring>
#include<map>
#define maxn 100010
#define p 31
using namespace std;
typedef unsigned long long ll;
struct Tree{
int l,r;
ll hashes;
}tree[300000];
char str[2000100];
ll hh[maxn];
void init(){
int i;
hh[0]=1;
for(i=1;i<=maxn;i++)
hh[i]=hh[i-1]*p;
}
ll calhash(){
int i,len=strlen(str);
ll sum=0;
for(i=len-1;i>=0;i--)
sum=sum*p+str[i]-'a'+1;
return sum;
}
void build(int s,int t,int id){
tree[id].l=s;tree[id].r=t;
if(s==t){
tree[id].hashes=str[s]-'a'+1;
return;
}
int mid=(s+t)>>1;
build(s,mid,id<<1);
build(mid+1,t,id<<1|1);
tree[id].hashes=tree[id<<1].hashes+tree[id<<1|1].hashes*hh[mid+1-s];
}
void update(int l,int id){
if(tree[id].l==tree[id].r){
tree[id].hashes=str[l]-'a'+1;
return ;
}
int mid=(tree[id].l+tree[id].r)>>1;
if(l<=mid) update(l,id<<1);
else update(l,id<<1|1);
tree[id].hashes=tree[id<<1].hashes+tree[id<<1|1].hashes*hh[mid+1-tree[id].l];
}
ll query(int s,int t,int id){
if(tree[id].l>=s && tree[id].r<=t)
return tree[id].hashes;
int mid=(tree[id].l+tree[id].r)>>1;
if(t<=mid) return query(s,t,id<<1);
else if(s>mid) return query(s,t,id<<1|1);
return query(s,mid,id<<1)+query(mid+1,t,id<<1|1)*hh[mid+1-s];
}
int main(){
int t,T,pos,l,r,i,q,n;
char s1[10],s2[10];
map<ll,int>mp;
init();
scanf("%d",&T);
for(t=1;t<=T;t++){
printf("Case #%d:\n",t);
scanf("%d",&n);
mp.clear();
for(i=1;i<=n;i++){
scanf("%s",str);
mp.insert(make_pair(calhash(),1));
}
scanf("%s",str);
int len=strlen(str);
build(0,len-1,1);
scanf("%d",&q);
for(i=1;i<=q;i++){
scanf("%s",s1);
if(s1[0]=='C'){
scanf("%d%s",&pos,s2);
str[pos]=s2[0];
update(pos,1);
}
else{
scanf("%d %d",&l,&r);
if(mp.find(query(l,r,1))!=mp.end()) printf("Yes\n");
else printf("No\n");
}
}
}
}