原题:http://acm.hdu.edu.cn/showproblem.php?pid=3973
题解:m组询问子串是否出现过,和单点修改。将字符串哈希,放进线段树合并就可以了,根据下面的公式合并就行了
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ull unsigned long long
using namespace std;
const int N=1e5+10;
const int M=31;
int cas,n,len,m,cnt;
char s[2200000],str[N];
ull p[N],tt[N<<2],a[N];
//map<ull,bool> mp;
inline int ls(int x){return x<<1;}
inline int rs(int x){return x<<1|1;}
void build(int now,int l,int r){
if(l==r) { tt[now]=s[l]-'a'+1;return ;}
else{
int mid=(l+r)>>1;
build(ls(now),l,mid);
build(rs(now),mid+1,r);
tt[now]=tt[ls(now)]*p[r-mid]+tt[rs(now)];
}
}
ull query(int now,int l,int r,int x,int y){
if(x<=l && r<= y){return tt[now];}
ull a1=0,a2=0,ans=0;
int mid=(l+r)>>1;
if(x<=mid) a1=query(ls(now),l,mid,x,y);
if(mid<y) a2=query(rs(now),mid+1,r,x,y);
return a1*p[max(0,min(y,r)-mid)]+a2;
}
void change(int now,int l,int r,int pos,int c){
if(l==pos && r==pos){tt[now]=c;return ;}
int mid=(l+r)>>1;
if(pos<=mid) change(ls(now),l,mid,pos,c);
if(mid<pos) change(rs(now),mid+1,r,pos,c);
tt[now]=tt[ls(now)]*p[r-mid]+tt[rs(now)];
}
bool check(ull x){
for(int i=1;i<=n;i++)if(x==a[i]){return 1;}
return 0;
}
int main(){
// freopen("hdu3973.in","r",stdin);
p[0]=1;for(int i=1;i<=1e5;i++) p[i]=p[i-1]*M;
scanf("%d",&cas);cnt=0;
while(cas--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
ull hash=0;
for(int j=1;j<=strlen(s+1);j++) {
hash=hash*M+s[j]-'a'+1;
}
a[i]=hash;
}
scanf("%s%d",s+1,&m);len=strlen(s+1);
build(1,1,len);
printf("Case #%d:\n",++cnt);
for(int i=1,l,r;i<=m;i++){
scanf("%s%d",str,&l);l++;
if(str[0]=='Q'){
scanf("%d",&r);r++;
ull ch=query(1,1,len,l,r);
bool flag=1;
flag=check(ch);
printf("%s\n",flag?"Yes":"No");
}else{
scanf("%s",str);
change(1,1,len,l,str[0]-'a'+1);
}
}
}
return 0;
}