URAL 1989 Subpalindromes (多项式hash) +【线段树】
<题目链接>
<转载于 >>> >
题目大意:
给你一段字符串,进行两种操作:
1.询问[l,r]这个区间中的字符串是否是回文串;
2.更改该字符串中对应下标的字符。
解题分析:
快速判断字符串是不是回文串,可以用到多项式Hash。假设一个串s,那么字串s[i, j]的Hash值就是H[i, j]=s[i]+s[i+1]*x+s[i+2]*(x^2)+...+s[j]*(x^(j-i))。由于只有小写字母,因此x取27。但是H[i, j]这会很大,我们取模就可了,可以把变量类型设为unsigned long long, 那么自动溢出就相当于模2^64了。对于不同串但是Hash相同的情况,这种情况的概率是非常小的,通常可以忽略,当然我们也可以对x取多次值,求出不同情况下的Hash值。然后我们就可以用线段树或者树状数组来维护这个和了,复杂度O(nlogn)。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 #define Lson rt<<1,l,mid 7 #define Rson rt<<1|1,mid+1,r 8 #define N 100005 9 #define ull unsigned long long 10 ull f[N]; 11 char s[N]; 12 int n; 13 struct Tree{ 14 ull lsum,rsum; //左->右和右->左的hash值 15 }tr[N<<2]; 16 void Pushup(int rt){ //将该区间内从左到右和从右到左的多项式hash的每一位相加 17 tr[rt].lsum=tr[rt<<1].lsum+tr[rt<<1|1].lsum; 18 tr[rt].rsum=tr[rt<<1].rsum+tr[rt<<1|1].rsum; 19 } 20 void build(int rt,int l,int r){ 21 if(l==r){ 22 tr[rt].lsum=f[l-1]*(s[l-1]-'a'); //得到hash多项式相应位置的hash值 23 tr[rt].rsum=f[n-l]*(s[l-1]-'a'); 24 return; 25 } 26 int mid=(l+r)>>1; 27 build(Lson); 28 build(Rson); 29 Pushup(rt); 30 } 31 void update(int rt,int l,int r,int pos,int num){ 32 if(l==r){ 33 tr[rt].lsum=f[l-1]*num; 34 tr[rt].rsum=f[n-l]*num; 35 return; 36 } 37 int mid=(l+r)>>1; 38 if(pos<=mid)update(Lson,pos,num); 39 if(pos>mid)update(Rson,pos,num); 40 Pushup(rt); 41 } 42 ull lsum,rsum; 43 void query(int rt,int l,int r,int L,int R){ 44 if(L<=l&&r<=R){ 45 lsum+=tr[rt].lsum; 46 rsum+=tr[rt].rsum; 47 return; 48 } 49 int mid=(l+r)>>1; 50 if(L<=mid)query(Lson,L,R); 51 if(R>mid)query(Rson,L,R); 52 } 53 int main(){ 54 f[0]=1; 55 for(int i=1;i<N;i++) 56 f[i]=f[i-1]*27; //预处理27的1~N次方 57 while(scanf("%s",s)!=EOF){ 58 n=strlen(s); 59 build(1,1,n); 60 int q;scanf("%d",&q); 61 while(q--){ 62 scanf("%s",s); 63 if(s[0]=='p'){ 64 int x,y;scanf("%d%d",&x,&y); 65 lsum=rsum=0; 66 query(1,1,n,x,y); 67 int k1=x-1; 68 int k2=n-y; 69 if(k1>k2)rsum*=f[k1-k2]; //按照上面的计算方式,从左向右和从右向左的相同hash多项式的计算中,短区域中的每一项会比长区域少乘f[k1-k2](或f[k2-k1])次方,所以这里要讲相差的f[]乘上,再进行比较 70 else lsum*=f[k2-k1]; 71 if(lsum==rsum)printf("Yes\n"); 72 else printf("No\n"); 73 } 74 else{ 75 int x; 76 scanf("%d%s",&x,s); 77 update(1,1,n,x,s[0]-'a'); 78 } 79 } 80 } 81 }
2018-10-31
作者:is_ok
出处:http://www.cnblogs.com/00isok/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。