http://acm.hdu.edu.cn/showproblem.php?pid=3973
题意
给一个词典和一个主串。有两种操作,查询主串某个区间,问这主串区间中包含多少词典中的词语。修改主串某一位置的字符。
分析
题目要求区间查询,和单点更新,那么最先想到的应该是线段树。可字符串怎么利用线段树呢?用hash!首先将词典按规则hash后放入map,然后将主串的hash值放置入线段树中。问题来了,怎么更新结点的hash值呢?假如现在我们知道了s[l...mid]和s[mid+1...r]的hash值,我需要s[l...r]的hash值,根据我的hash规则(将主串看作是p进制数,左边为高位,p为素数),hash[l...r]=hash[l...mid]*p^(r-mid)+hash[mid+1...r]。另外,被输入卡了好久。。不停RE。需要使用更准确的输入格式,我猜测可能是输入数据之间的空格不定导致的。
#include<iostream> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<cstdio> #include<algorithm> #include<map> #include<set> #define rep(i,e) for(int i=0;i<(e);i++) #define rep1(i,e) for(int i=1;i<=(e);i++) #define repx(i,x,e) for(int i=(x);i<=(e);i++) #define X first #define Y second #define PB push_back #define MP make_pair #define mset(var,val) memset(var,val,sizeof(var)) #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define pd(a) printf("%d ",a) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define IOS ios::sync_with_stdio(false);cin.tie(0) #define lc idx<<1 #define rc idx<<1|1 #define lson l,mid,lc #define rson mid+1,r,rc using namespace std; typedef long long ll; template <class T> void test(T a){cout<<a<<endl;} template <class T,class T2> void test(T a,T2 b){cout<<a<<" "<<b<<endl;} template <class T,class T2,class T3> void test(T a,T2 b,T3 c){cout<<a<<" "<<b<<" "<<c<<endl;} const int N = 1e6+10; const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3fll; const ll mod = 1000000007; int T; void testcase(){ printf("Case #%d: ",++T); } const int MAXN = 1e5+10; const int MAXM = 30; const int p = 19; struct node{ int l,r; ll hass; }tree[MAXN<<2]; char str[2000010]; ll P[MAXN]; map<ll,int> ma; int n; void init(){ P[0]=1; for(int i=1;i<MAXN;i++){ P[i]=p*P[i-1]; } } void Hash(char s[]){ int len = strlen(s); ll res=0; for(int i=0;i<len;i++){ res +=P[len-1-i]*(s[i]-'a'+1); } ma[res]=1; } void push_up(int m,int idx){ tree[idx].hass=tree[lc].hass*P[m]+tree[rc].hass; } void build(int l,int r,int idx){ tree[idx].l=l,tree[idx].r=r; if(l==r){ tree[idx].hass=str[l]-'a'+1; return; } int mid = (l+r)>>1; build(lson); build(rson); push_up(r-mid,idx); } void update(int pos,int idx){ if(tree[idx].l==tree[idx].r){ tree[idx].hass=str[pos]-'a'+1; return; } int mid = (tree[idx].l+tree[idx].r)>>1; if(pos<=mid) update(pos,lc); else update(pos,rc); push_up(tree[idx].r-mid,idx); } ll query(int l,int r,int idx){ if(tree[idx].l>=l&&tree[idx].r<=r) return tree[idx].hass; int mid = (tree[idx].l+tree[idx].r)>>1; if(r<=mid) return query(l,r,lc); else if(l>mid) return query(l,r,rc); return query(l,mid,lc)*P[r-mid]+query(mid+1,r,rc); } int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL int t,m; scd(t); init(); T=0; char s1[10],s2[10]; while(t--){ testcase(); ma.clear(); scd(n); for(int i=0;i<n;i++){ scanf("%s",str); Hash(str); } scanf("%s",str); int len = strlen(str); build(0,len-1,1); scd(m); while(m--){ scanf("%s",s1); if(s1[0]=='Q'){ int l,r; scdd(l,r); if(ma.find(query(l,r,1))!=ma.end()) puts("Yes"); else puts("No"); }else{ int pos; scanf("%d%s",&pos,s2); str[pos]=s2[0]; update(pos,1); } } } return 0; }