题意:给出n个模式串和一个母串 然后修改操作是修改母串中的某一个字母 询问操作是给出一堆的区间 然后问这个区间是否满足n个模式串中的一个
解法:修改的话就是线段树的单点修改 关键在于O(1)判断字符串 那么我们采用字符串hash就可以了
把字符串看成一个素数进制的数 然后预处理每一位的位权 我们就可以把n个模式串全部保存在map里面 然后就可以判断是否存在了
对于线段数,当然是储存每一个区间的hash值了
当然这一题应该还有更好的做法 就是纯字符串的判断 这个先学习下
#include<map>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long
#define maxn 222222
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
#define mul 27
map<ll,int>mp;
char ss[maxn*2];
ll ha[maxn<<2],p[maxn];
int scan()
{
int res=0,ch;
while(!((ch= getchar())>='0'&&ch<='9')){
if(ch==EOF)return 1<<30;
}
res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch-'0');
return res;
}
void val(){
int len=(int)strlen(ss); ll ans=0;
for(int i=0;i<len;++i)ans+=(ss[i]-'a'+1)*p[len-i-1];
mp[ans]=1;
}
int n,m,a,b;
char op[111];
void up(int rt,int l,int r){ha[rt]=ha[ls]*p[r-mid]+ha[rs];}
void build(int rt,int l,int r){
if(l==r){ha[rt]=ss[l]-'a'+1;return ;}
build(ls,l,mid);
build(rs,mid+1,r);
up(rt,l,r);
}
void ins(int rt,int l,int r,int pos,char x){
if(l==r){ha[rt]=x-'a'+1;return ;}
if(pos<=mid)ins(ls,l,mid,pos,x);
if(mid<pos)ins(rs,mid+1,r,pos,x);
up(rt,l,r);
}
ll query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R)return ha[rt];
if(R<=mid)return query(ls,l,mid,L,R);
else if(mid<L)return query(rs,mid+1,r,L,R);
else{
ll ansl=query(ls,l,mid,L,mid),ansr=query(rs,mid+1,r,mid+1,R);
return ansl*(p[R-mid])+ansr;
}
}
int main(){
int _;_=scan();
ll ans=1;
for(int i=0;i<200005;++i)p[i]=ans,ans*=mul;
for(int z=1;z<=_;++z){
mp.clear();
scanf("%d",&n);
while(n--)scanf("%s",ss),val();
scanf("%s%d",ss+1,&m);n=(int)strlen(ss+1);
build(1,1,n);printf("Case #%d:\n",z);
while(m--){
scanf("%s",op);
if(*op=='Q'){
a=scan(),b=scan();++a,++b;
ll ans=query(1,1,n,a,b);
if(mp[ans])printf("Yes\n");
else printf("No\n");
}else if(*op=='C'){
a=scan();
scanf("%s",op);++a;
ins(1,1,n,a,op[0]);
}
}
}
return 0;
}