hdu3973 线段树+哈希

原题:http://acm.hdu.edu.cn/showproblem.php?pid=3973

题解:m组询问子串是否出现过,和单点修改。将字符串哈希,放进线段树合并就可以了,根据下面的公式合并就行了tt[now]=tt[now<<1]*p^{Rslen}+tt[now<<1|1]

#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;
}

猜你喜欢

转载自blog.csdn.net/weixin_39689721/article/details/87472930